Laden...

RESTful-Umsetzung von partiellen Ressourcen-Updates (PATCH)

Erstellt von emuuu vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.136 Views
emuuu Themenstarter:in
286 Beiträge seit 2011
vor 5 Jahren
RESTful-Umsetzung von partiellen Ressourcen-Updates (PATCH)

Guten Tag zusammen,

wie der Titel schon sagt möchte ich eine Ressource gerne teilweise updaten und das ganze restful umsetzen.

Ich bin mir jetzt nicht 100% sicher wie ein richtiger Ansatz hier aussehen würde, daher folgende Beispiel:


public class OrderModel
{
public int Id {get;set;}

public string Description {get;set}

public string OrderNumber {get;set;}
}

Ich möchte nun Description und OrderNumber unabhängig von einander updaten.

Die erste Frage die sich mir nun stellt: Darf ich zwei verschiedene Routen nehmen, um dies umzusetzen oder muss ich bei "PATCH /orders/{id}" bleiben.
In letzterem Fall müsste ich mir aus dem Model die Felder raussuchen die nicht null sind und dann jeweils separate Funktionen aufrufen.
Gerade wenn die Ressource aber komplexer wird erscheint mir das unnötig kompliziert. Auch in Bezug auf die Client-Entwicklung sehe ich das als problematisch, da ja nur schwer ersichtlich ist, ob für ein bestimmtest Feld (oder einen Satz Felder) das PATCH-Update überhaupt implementiert ist.

Die andere Option wäre in etwa sowas:
PATCH /orders/{id}/description
PATCH /orders/{id}/ordernumber
(Nebenfrage für dieses Szenario: Müsste es dann nicht eigentlich PUT sein, da ich nicht Order patche sondern die Ressource "Description zu Order XY" überschreibe?)

Die zweite Frage ist nun:
Muss ich bei PATCH immer das Model senden oder kann ich z.B. sowas machen:

[HttpPatch]
[Route("orders/{orderID}/description")]
public async Task<IActionResult> UpdateOrderDescription(int orderID, [FromBody] string description)

Wenn ich immer das Model senden müsste erscheint mir die Verwendung einer URI redundant, da ich die ID ja ohnehin direkt mit Model mitsenden könnte.

So ich hoffe ich konnte meine Verständnisfrage einigermaßen gut formulieren.
Vielen Dank schonmal und beste Grüße
emuuu

2+2=5( (für extrem große Werte von 2)

16.834 Beiträge seit 2008
vor 5 Jahren

Die erste Frage die sich mir nun stellt: Darf ich zwei verschiedene Routen nehmen, um dies umzusetzen oder muss ich bei "PATCH /orders/{id}" bleiben.

URL bleibt identisch.

Normalerweise verwendet man aber nicht die Properties direkt, sondern Patch-Models.
Also Klassen, die genau dem Patch entsprechen.

public clas OrderDescriptionPatchModel
{
   prop Description
}

In letzterem Fall müsste ich mir aus dem Model die Felder raussuchen die nicht null sind und dann jeweils separate Funktionen aufrufen.

Nein. Damit könntest Du nichts null setzen.

Die andere Option wäre in etwa sowas:
PATCH /orders/{id}/description
PATCH /orders/{id}/ordernumber

Das ist gegen REST.

Müsste es dann nicht eigentlich PUT sein, da ich nicht Order patche sondern die Ressource "Description zu Order XY" überschreibe?)

Nein, PUT und POST sind beides Verben für das Hinzufügen vollständiger Modelle/Entitäten.
Der Unterschied ist nur, dass PUT idempotent ist, und POST nicht.

Muss ich bei PATCH immer das Model senden oder kann ich z.B. sowas machen:

Gegen REST, daher schließt es sich aus.

2.207 Beiträge seit 2011
vor 5 Jahren

Hallo emuuu,

es gibt ein JsonPatchDocument, das eine Methode ApplyTo(...) sowie Methoden für die anderen PATCH-Operationen hat.

[HttpPatch("{id:int}", Name = nameof(PartiallyUpdateSomething))]
public IActionResult PartiallyUpdateSomething(int id, [FromBody] JsonPatchDocument<MyUpdateDto> patchDoc)
{
	// 
	
	MyUpdateDto updateDto = Mapper.Map<MyUpdateDto>(existingEntity);
	patchDoc.ApplyTo(updateDto, ModelState);
	
	// ...
}

Das hilft dir sowas zu machen.

Gruss

Coffeebean

emuuu Themenstarter:in
286 Beiträge seit 2011
vor 5 Jahren

Perfekt, vielen Dank!

Eine weitere Frage hätte ich noch:
Wenn ich im Model z.B. eine Auflistung habe und diese ergänzen bzw. kürzen möchte, muss ich hier ebenfalls ein Patch-Model erstellen oder gibt es eine REST konforme Abkürzung hierfür?

Ich meine z.B. sowas:


public async Task GrantRole(string userID, string roleID)
{
//..
}

public async Task RevokeRole(string userID, string roleID)
{
//..
}

Darf man das so umsetzen oder muss ich immer das PatchModel senden:


public class UserPatchModel
{
IEnumerable<RoleModel> Roles;
}

Vielen Dank und beste Grüße
emuuu

2+2=5( (für extrem große Werte von 2)