Stellen Sie sich vor, Sie haben zwei Einheiten, Spieler und Team , in denen Spieler mehreren Teams angehören können. In meinem Datenmodell habe ich eine Tabelle für jede Entität und eine Verknüpfungstabelle, um die Beziehungen aufrechtzuerhalten. Hibernate kann damit gut umgehen, aber wie kann ich diese Beziehung in einer RESTful-API verfügbar machen?
Ich kann mir ein paar Möglichkeiten vorstellen. Erstens könnte jede Entität eine Liste der anderen enthalten, sodass ein Spielerobjekt eine Liste der Teams enthält, zu denen es gehört, und jedes Teamobjekt eine Liste der Spieler, die dazu gehören. Um einen Spieler zu einem Team hinzuzufügen, POSTEN Sie einfach die Darstellung des Spielers an einen Endpunkt, z. B. POST /player
oder POST, /team
mit dem entsprechenden Objekt als Nutzlast der Anforderung. Dies scheint mir das "RESTful" zu sein, fühlt sich aber etwas komisch an.
/api/team/0:
{
name: 'Boston Celtics',
logo: '/img/Celtics.png',
players: [
'/api/player/20',
'/api/player/5',
'/api/player/34'
]
}
/api/player/20:
{
pk: 20,
name: 'Ray Allen',
birth: '1975-07-20T02:00:00Z',
team: '/api/team/0'
}
Die andere Möglichkeit, dies zu tun, besteht darin, die Beziehung als eigenständige Ressource herauszustellen. /playerteam/team/{id}
Um eine Liste aller Spieler in einem bestimmten Team anzuzeigen, können Sie ein GET oder ähnliches durchführen und eine Liste der PlayerTeam-Entitäten zurückerhalten. Um einen Spieler zu einem Team hinzuzufügen, POST /playerteam
mit einer entsprechend erstellten PlayerTeam-Entität als Nutzlast.
/api/team/0:
{
name: 'Boston Celtics',
logo: '/img/Celtics.png'
}
/api/player/20:
{
pk: 20,
name: 'Ray Allen',
birth: '1975-07-20T02:00:00Z',
team: '/api/team/0'
}
/api/player/team/0/:
[
'/api/player/20',
'/api/player/5',
'/api/player/34'
]
Was ist die beste Vorgehensweise dafür?
quelle
Ich würde eine solche Beziehung mit Subressourcen abbilden, allgemeines Design / Durchqueren wäre dann:
In Restful-Begriffen hilft es sehr, nicht an SQL zu denken und sich zu verbinden, sondern mehr in Sammlungen, Untersammlungen und Traversal.
Einige Beispiele:
Wie Sie sehen, verwende ich POST nicht, um Spieler in Teams zu platzieren, sondern PUT, das Ihre n: n-Beziehung zwischen Spielern und Teams besser handhabt.
quelle
status
als Parameter in PUT-Anfrage senden ? Gibt es einen Nachteil bei diesem Ansatz?Die vorhandenen Antworten erklären nicht die Rollen von Konsistenz und Idempotenz - die ihre Empfehlungen von
UUIDs
/ Zufallszahlen für IDs undPUT
stattdessen motivierenPOST
.Wenn wir den Fall betrachten, in dem wir ein einfaches Szenario wie " Hinzufügen eines neuen Spielers zu einem Team " haben, treten Konsistenzprobleme auf.
Da der Spieler nicht existiert, müssen wir:
Sollte der Client-Vorgang jedoch nach dem
POST
to fehlschlagen/players
, haben wir einen Spieler erstellt, der keinem Team angehört:Jetzt haben wir einen verwaisten doppelten Spieler in
/players/5
.Um dies zu beheben, schreiben wir möglicherweise einen benutzerdefinierten Wiederherstellungscode, der nach verwaisten Spielern sucht, die einem natürlichen Schlüssel entsprechen (z
Name
. B. ). Dies ist benutzerdefinierter Code, der getestet werden muss, mehr Geld und Zeit kostet usw. usw.Um zu vermeiden, dass benutzerdefinierter Wiederherstellungscode benötigt wird, können wir
PUT
stattdessen implementierenPOST
.Aus dem RFC :
Damit eine Operation idempotent ist, müssen externe Daten wie vom Server generierte ID-Sequenzen ausgeschlossen werden. Aus diesem Grund empfehlen die Leute beide
PUT
undUUID
s fürId
s zusammen.Dies ermöglicht es uns, sowohl das
/players
PUT
als auch das/memberships
PUT
ohne Konsequenzen erneut auszuführen :Alles ist in Ordnung und wir mussten nichts weiter tun, als es für Teilausfälle erneut zu versuchen.
Dies ist eher ein Nachtrag zu den bestehenden Antworten, aber ich hoffe, dass sie in den Kontext des Gesamtbildes gestellt werden, wie flexibel und zuverlässig ReST sein kann.
quelle
23lkrjrqwlej
?Meine bevorzugte Lösung besteht darin, drei Ressourcen zu erstellen :
Players
,Teams
undTeamsPlayers
.Um alle Spieler eines Teams zu gewinnen, gehen Sie einfach zur
Teams
Ressource und rufen Sie alle Spieler anGET /Teams/{teamId}/Players
.Um alle Teams zu erhalten, die ein Spieler gespielt hat, erhalten Sie die
Teams
Ressource innerhalb derPlayers
. Rufen Sie anGET /Players/{playerId}/Teams
.Und um die Viele-zu-Viele-Beziehung anzurufen
GET /Players/{playerId}/TeamsPlayers
oderGET /Teams/{teamId}/TeamsPlayers
.Beachten Sie, dass Sie in dieser Lösung beim Aufrufen
GET /Players/{playerId}/Teams
eine Reihe vonTeams
Ressourcen erhalten, die genau dieselbe Ressource sind, die Sie beim Aufrufen erhaltenGET /Teams/{teamId}
. Das Gegenteil folgt dem gleichen Prinzip:Players
Beim Aufruf erhalten Sie eine Reihe von RessourcenGET /Teams/{teamId}/Players
.Bei beiden Aufrufen werden keine Informationen zur Beziehung zurückgegeben. Beispielsweise wird no
contractStartDate
zurückgegeben, da die zurückgegebene Ressource keine Informationen über die Beziehung enthält, sondern nur über ihre eigene Ressource.Um mit der nn-Beziehung umzugehen, rufen Sie entweder
GET /Players/{playerId}/TeamsPlayers
oder anGET /Teams/{teamId}/TeamsPlayers
. Diese Aufrufe geben die genaue Ressource zurückTeamsPlayers
.Diese
TeamsPlayers
Ressource hatid
,playerId
,teamId
Attribute, sowie einige andere , die die Beziehung zu beschreiben. Außerdem verfügt es über die erforderlichen Methoden, um mit ihnen umzugehen. GET, POST, PUT, DELETE usw., die die Beziehungsressource zurückgeben, einschließen, aktualisieren und entfernen.Die
TeamsPlayers
Ressource implementiert einige Abfragen, z. B.GET /TeamsPlayers?player={playerId}
um alleTeamsPlayers
Beziehungen zurückzugeben, die der Spieler identifiziert{playerId}
hat. Verwenden SieGET /TeamsPlayers?team={teamId}
nach der gleichen Idee, um alleTeamsPlayers
im{teamId}
Team gespielten Daten zurückzugeben. Bei beidenGET
Aufrufen wird die RessourceTeamsPlayers
zurückgegeben. Alle Daten, die sich auf die Beziehung beziehen, werden zurückgegeben.Beim Aufrufen
GET /Players/{playerId}/Teams
(oderGET /Teams/{teamId}/Players
) ruft die RessourcePlayers
(oderTeams
)TeamsPlayers
auf, um die zugehörigen Teams (oder Spieler) mithilfe eines Abfragefilters zurückzugeben.GET /Players/{playerId}/Teams
funktioniert so:Sie können denselben Algorithmus verwenden, um alle Spieler aus einem Team zu holen, wenn Sie anrufen
GET /Teams/{teamId}/Players
, aber Teams und Spieler austauschen.Meine Ressourcen würden folgendermaßen aussehen:
Diese Lösung basiert nur auf REST-Ressourcen. Obwohl einige zusätzliche Aufrufe erforderlich sein können, um Daten von Spielern, Teams oder deren Beziehung abzurufen, lassen sich alle HTTP-Methoden problemlos implementieren. POST, PUT, DELETE sind einfach und unkompliziert.
Jedes Mal, wenn eine Beziehung erstellt, aktualisiert oder gelöscht wird, werden beide
Players
undTeams
Ressourcen automatisch aktualisiert.quelle
Ich weiß, dass es eine Antwort gibt, die als akzeptiert für diese Frage markiert ist. Hier ist jedoch, wie wir die zuvor aufgeworfenen Probleme lösen können:
Sagen wir für PUT
Beispielsweise führen die folgenden Schritte alle zum gleichen Effekt, ohne dass eine Synchronisierung erforderlich ist, da sie für eine einzelne Ressource ausgeführt werden:
Wenn wir nun mehrere Mitgliedschaften für ein Team aktualisieren möchten, können wir Folgendes tun (mit den richtigen Validierungen):
quelle
Ich bevorzuge 2
quelle