Was ist das beste Muster für das Hinzufügen eines vorhandenen Elements zu einer Sammlung in der REST-API?

23

Ich entwerfe eine pragmatische REST-API und bin ein wenig überlegt, wie vorhandene Entitäten einer Sammlung am besten hinzugefügt werden können. Mein Domain-Modell enthält ein Projekt mit einer Sammlung von Websites. Dies ist eine strenge Viele-zu-Viele-Beziehung, und ich muss keine Entität erstellen, die die Beziehung explizit modelliert (z. B. ProjectSite).

Meine API ermöglicht es Verbrauchern, eine vorhandene Site zu einem Projekt hinzuzufügen. Wo ich aufgehängt werde, ist, dass die einzigen Daten, die ich wirklich brauche, ProjectId und SiteId sind. Meine ursprüngliche Idee war:

1. POST myapi/projects/{projectId}/sites/{siteId}

Aber ich habe auch darüber nachgedacht

2. POST myapi/projects/{projectId}/sites

mit einer Site-Entität, die als JSON-Inhalt gesendet wurde.

Option 1 ist einfach und funktioniert, fühlt sich aber nicht richtig an. Ich habe andere Beziehungen, die diesem Muster nicht folgen können, sodass meine API inkonsistent wird.

Option 2 fühlt sich besser an, führt aber zu zwei Bedenken:

  • Soll ich eine Site erstellen oder eine Ausnahme auslösen, wenn eine neue Site veröffentlicht wird (SiteId = 0)?
  • Da ich zum Erstellen der Beziehung nur ProjectId und SiteId benötige, wird die Site möglicherweise mit falschen oder fehlenden Daten für andere Eigenschaften gepostet.

Eine dritte Option besteht darin, einen einfachen Endpunkt ausschließlich zum Erstellen und Löschen der Beziehung bereitzustellen. Dieser Endpunkt würde eine JSON-Nutzlast erwarten, die nur ProjectId und SiteId enthält.

Was denkst du?

Jamie Ide
quelle
2
Siehe auch: stackoverflow.com/questions/2001773/…
Rory Hunter
@RoryHunter In diesem Link gibt es einige interessante Diskussionen, aber nichts, was meine Unsicherheit beseitigt. Besonders gefällt mir, dass die akzeptierte Antwort lautet: "Sie haben richtig verstanden." und der 2. Platz (wenn auch mit großem Abstand) mit "Einfach ausgedrückt, machen Sie das komplett rückwärts."
Jamie Ide
Ihre erste Option ist in Ordnung, obwohl ich PUT anstelle von POST verwenden würde, da der Client die Kontrolle über die Identität hat, die der Sammlung hinzugefügt wird. Ihre erste Sorge mit Option 2 liegt ganz bei Ihnen. Wenn Sie keine neuen Websites möchten, lösen Sie keine Ausnahme aus, sondern geben Sie einen der 4xx-Codes zurück. Ihre zweite Sorge ist weder hier noch da. Sie sollten ohnehin nicht die gesamte Site veröffentlichen, es sei denn, Sie lassen Ergänzungen zu. Das Hinzufügen einer vorhandenen Site sollte nur die ID enthalten, wenn Sie die Site ändern, sondern nur die Auflistung "ProjectSite" (auch wenn Sie keine separate Ressource dafür erstellen).
Marjan Venema

Antworten:

14

POST ist das "Anhängen" -Verb und auch das "Verarbeiten" -Verb. PUT ist das Verb "create / update" (für bekannte Bezeichner) und scheint hier fast die richtige Wahl zu sein, da der vollständige Ziel-URI bekannt ist. projectIdund sind siteIdbereits vorhanden, sodass Sie nicht in eine Sammlung POSTEN müssen, um eine neue ID zu erstellen.

Das Problem bei PUT ist, dass der Body die Repräsentation der Ressource sein muss, die Sie PUTting. Die Absicht hierbei ist jedoch, an die Sammlungsressource "project / sites" anzuhängen, anstatt die Site-Ressource zu aktualisieren.

Was passiert, wenn jemand eine vollständige JSON-Darstellung einer vorhandenen Site erstellt? Sollten Sie die Auflistung und das Objekt aktualisieren? Sie könnten das unterstützen, aber es hört sich so an, als wäre das nicht die Absicht. Wie du gesagt hast,

Die einzigen Daten, die ich wirklich brauche, sind ProjectId und SiteId

Stattdessen würde ich versuchen, das POST siteIdin die Auflistung einzutragen , und mich auf die Eigenschaften "Anhängen" und "Verarbeiten" von POST verlassen:

POST myapi / projects / {projectId} / sites

{'Ich würde': '...' }

Da Sie die Websites sind zu modifizieren Sammlung Ressource und nicht die Website - Ressource , das ist die URI Sie wollen. Der POST kann "anhängen / verarbeiten" und das Element mit dieser ID zur Websitesammlung des Projekts hinzufügen.

Dadurch bleibt die Tür für die Erstellung brandneuer Sites für das Projekt offen, indem der JSON-Code konkretisiert und die ID weggelassen wird. "Keine ID" == "Von Grund auf neu erstellen". Wenn die Auflistungs-URI jedoch eine ID und nichts anderes erhält, ist ziemlich klar, was passieren muss.

Interessante Frage. :)

rauben
quelle
Ich bin der Überzeugung, dass POST für das Erstellen und PUT für das Aktualisieren bestimmt ist, aber Ihre Schlussfolgerung ist, wo ich gestern gelandet bin. Das Schöne ist, dass ich dank Attribut-Routing in der Web-API den Code in einem ProjectSites-Controller habe, damit der Code gut organisiert ist.
Jamie Ide
Ich denke, der entscheidende Grund, den Sie POSTanstelle von PUToder PATCHhier verwenden müssen, ist, dass Sie nicht die gesamte SiteEntität für die sitesRessource haben. Sie haben nur die ID, die verarbeitet werden muss, um sie der Sammlung hinzuzufügen.
Crush
4

Wir verwenden die PatchMethode für solche Dinge. Sie möchten ein vorhandenes Projekt ändern, um ihm eine Site hinzuzufügen.

So etwas würde funktionieren

PATCH myapi/projects/{id} 

mit der Site (s) -Entität als JSON / JSONArray im Anforderungshauptteil.

Auf diese Weise können Sie bei Bedarf dieselbe URL verwenden, um verschiedene Teile des Projekts zu ändern - Ihr Code in der Implementierung muss intelligent genug sein, um diese teilweise Änderung der Ressource zu verarbeiten.

Juan
quelle
Interessanter Ansatz. Ich habe ein "reiches" (dh stark abhängiges) älteres Domain-Modell und Project hat besonders viele Sammlungen, die daran hängen. Das Ermitteln des in der Anforderung enthaltenen Entitätstyps wäre eine Herausforderung und passt nicht zu meinem pragmatischen Ziel.
Jamie Ide
Warum eine Herausforderung? Wenn Sie diese Einschränkungen haben, können Sie immer einen JSON verwenden, der explizit {"sites": [], "other-stuff": {}}angibt, was gesendet wird ... Sie können dann Ihren Code verzweigen, um alle diese "subjsons" sehr einfach zu behandeln. Es hängt wirklich von Ihrem spezifischen Problem ab, aber ich würde immer noch die Verwendung von PATCH empfehlen, da es speziell für diese Art von Dingen entwickelt wurde.
juan
Die Nachteile, die ich sehe, sind 1) API teilt nicht explizit mit, welche Sammlungen Änderungen zulassen; 2) kann die Bindung von Web-API-Parametern nicht nutzen; 3) großer Schalter oder if-Anweisung.
Jamie Ide
Ich habe die Patch-Methode noch nie zuvor gesehen
NimChimpsky
Würde nicht PATCHauch erwartet, dass die vollständige Entität hier als Wert übergeben wird, anstatt als ID, die auf eine Entität verweist?
Crush