Um eine Ressourcen-ID in die Nutzlast aufzunehmen oder von der URI abzuleiten

13

Beim Entwurf einer API haben wir uns die Frage gestellt, ob eine PUT-Payload die ID der zu aktualisierenden Ressource enthalten soll.

Dies ist, was wir derzeit haben:

PUT /users/123 Payload: {name: "Adrian"}

Unser Routencode extrahiert die ID aus der URI und fährt mit der Aktualisierung fort.

Die ersten Benutzer unserer API fragen sich, warum wir keine ID in der Nutzlast zulassen:

PUT /users/123 Payload: {id: 123, name: "Adrian"}

Der Grund, warum wir dies nicht zugelassen haben, ist, dass die ID in der Nutzlast und im URI dupliziert ist.

Wenn wir uns das genauer überlegen, verknüpfen wir die Ressource mit dem URI.

Wenn der URI nicht über die ID verfügt, muss die Nutzlast geändert werden:

PUT /no/id/here Payload: {name: "Adrian"} < What user???

Gibt es Gründe, dies nicht zu tun?

Adrian Lynch
quelle

Antworten:

14

Sie sollen den Uniform Resource Identifier mit der Ressource koppeln .

Wenn REST mit HTTP implementiert ist, rufen Sie mit GET den aktuellen Wert der Ressource ab und setzen mit PUT einen neuen Wert. Das GET hat keine Nutzlast, daher muss die Ressource durch den URI identifiziert werden. Und der PUT wird logisch mit demselben URI durchgeführt, und die Nutzdaten sollten genau so aussehen, wie Sie es sich wünschen, wenn das nächste GET zurückgibt.

Sie können POST für verschiedene URIs verwenden, dies ist jedoch weniger sinnvoll, da es unnötig asymmetrisch zum GET ist. Ein POST zu einer gemeinsamen URI kann nur sinnvoll sein, um neue Ressourcen ( POST /users/new, Nutzlast:, {name: "Adrian"}Antwort {id: 345, name: "Adrian"}) zu erstellen. Dies ist jedoch nicht idempotent und sollte daher vermieden werden wenn Sie REST anstreben¹. Stattdessen sollten Sie die ID mit einem Anruf reservieren und dann mit PUT die neue ID einstellen. Dies ist fehlertolerant, da bei einem Fehlschlagen der ersten Anforderung das Zeitlimit der ID-Reservierung möglicherweise überschritten wird und die ID-Reservierung nicht mehr PUTgültig ist. Oder verwenden Sie die vom Client generierte UUID.


¹ Die Definition von REST sagt nichts über die Idempotenz aus, daher kann ich nicht wirklich behaupten, dass es sich bei nicht-idempotenten Operationen nicht um REST handelt. Das ändert nichts an der Tatsache, dass das Festhalten an idempotenten Anforderungen die Zuverlässigkeit erhöht, ohne sie zu verkomplizieren, und wird daher empfohlen.

Jan Hudec
quelle
3
Soweit ich weiß, muss eine POST-Anfrage nicht idempotent sein. So sehe ich kein Problem mit dem Posten an /users(keine Notwendigkeit, 'neu' hinzuzufügen).
Lex82
Danke für deine Antwort. Ich sehe, dass es eine nette Funktion ist, für alle Anfragen die nötige Idempotenz zu haben, aber wer sagt, dass dies für eine REST-API erforderlich ist? Gewiss erlauben viele APIs, die sich RESTful nennen, nicht-idempotente POST-Anforderungen (insbesondere, wenn der Server IDs für neue Ressourcen generiert). Aber selbst wenn Sie eine sehr strenge Definition von REST anwenden, sehe ich nicht, welche architektonische Einschränkung bei nicht idempotenten POSTs wie im obigen Beispiel verletzt wird.
Lex82
Ich kann mir durchaus POST-Anfragen vorstellen, die eine Einschränkung verletzen. Ich verstehe nur nicht, warum das Posten einer Ressource in einer Sammlung und das Festlegen der ID durch den Server eine Verletzung der REST-Einschränkungen darstellt.
Lex82
Lassen Sie uns diese Diskussion im Chat fortsetzen .
Lex82
3
Die ganze Idee von POST ist nicht, idempotent zu sein ...
EralpB
2

Wenn wir uns das genauer überlegen, verknüpfen wir die Ressource mit dem URI.

Wenn der URI nicht über die ID verfügt, muss die Nutzlast geändert werden:

PUT / no / id / here Payload: {name: "Adrian"} <Welcher Benutzer ???

Gibt es Gründe, dies nicht zu tun?

Die Antwort auf diese Frage hängt davon ab, ob der Client die ID ändern darf.

Wenn der Client die ID über einen PUT ändern kann, ändert sich der URI für die Ressource, und Sie sollten einen Wert 301 dauerhaft verschoben angeben, wenn eine Ressource auf den alten URI zugreift.

So beginnt man zum Beispiel mit einer Ressource bei

/users/123

und der Client PUT das Folgende auf die Ressource

{id: 222, name: "Adrian"}

Die Ressource wurde aktualisiert und ihr URI ist jetzt

/users/222

Das LocationFeld in der PUT-Antwort sollte den neuen URI enthalten. Wenn Sie zu gehen, /users/123sollten Sie eine 301Antwort erhalten, wobei das Feld Location auf die neue /users/222Ressource verweist .

In den meisten Fällen möchten Sie jedoch nicht, dass der Client die ID ändern kann, da dies sehr schnell zu Problemen führen kann. In diesem Fall kann die ID nur vom Server geändert werden. Sie sollten sie aus dem PUT-Body herausnehmen, da der Client diesen Status nicht aktualisieren kann.

Wenn Sie eine Anforderung an einen anderen URI auf derselben Ressource eingeben, sagen Sie

/users/adian_lync

Wenn diese Ressource dann nicht vorhanden ist, sollte der Server sie erstellen und währenddessen eine ID erstellen

Cormac Mulhall
quelle
1
Der Grund, warum wir die Platzierung der ID in der Nutzlast in Frage stellten, war, dass Backbone.js die ID standardmäßig in einer PUT-Anforderung übergeben hat. Wir können das verhindern, aber jetzt möchte ich wissen, warum dies das Standardverhalten ist.
Adrian Lynch
1
Leider kenne ich Backbone.js nicht. Scheint unnötig, wenn die ID auch in der URL enthalten ist. Vielleicht ein Versehen seitens der Entwickler
Cormac Mulhall