In einer Java-REST-API mit PATCH vs PUT zum Aktualisieren einer Entität

Ich bin im Begriff, mit der Entwicklung einer neuen Rest-API in Java zu beginnen. Meine Frage ist über die Verwendung von PATCH - Warum?

Nehmen wir an, wir haben eine Entität namens Address.java

public class Address {

    @Id
    private Long id

    @NotNull
    private String line1;

    private String line2;       //optional

    @NotNull
    private String city;

    @NotNull
    private String state;   
}

Um eine neue Adresse zu erstellen, würde ich diese http-Anfrage ausführen:

POST http://localhost:8080/addresses

mit der folgenden Anfrage:

{
    "line1" : "mandatory Address line 1",
    "line2" : "optional  Address line 2",
    "city"  : "mandatory City",
    "state" : "cd"
}

Angenommen, der erstellte Datensatz hat eine ID 1

Die entsprechende @RestController AddressResource.java hat diese Methode:

@PostMapping(value = "/addresses")
public ResponseEntity<Address> create(@valid Address newAddress) {
    addressRepo.save(newAddress);
}

@ valid stellt sicher, dass die Entität gültig ist, bevor die Daten in der Tabelle gespeichert werden.

un nehme ich an, ich ziehe von meiner Wohnung oben zu einem Haus die Straße hinunter. Wenn ich einen PATCH verwende, wird dieser zu

PATCH http://localhost:8080/addresses/1

mit Nutzlast anfordern:

{
    "line1" : "1234 NewAddressDownTheStreet ST",
    "line2" : null
}

Die entsprechende @ RestController-Methode wäre:

@PatchMapping(value = "/addresses/{id}")
public ResponseEntity<Address> patchAddress(@PathVariable Long id, Address partialAddress) 
{
    Address dbAddress = addressRepo.findOne(id);
    if (partialAddress.getLine1() != null) {
        dbAddress.setLine1(partialAddress.getLine1());
    }
    if (partialAddress.getLine2() != null) {
        dbAddress.setLine2(partialAddress.getLine2());
    }
    if (partialAddress.getCity() != null) {
        dbAddress.setCity(partialAddress.getCity());
    }
    if (partialAddress.getState() != null) {
        dbAddress.setState(partialAddress.getState());
    }

    addressRepo.save(dbAddress)
}

Nun, wenn Sie die Tabelle abfragen, ist meine Adresse dann nicht?

"line1" : "1234 NewAddressDownTheStreet ST",
"line2" : "optional  Address line 2",       <-- INCORRECT. Should be null.
"city"  : "mandatory City",
"state" : "cd"

Wie zu sehen ist, führen die obigen Aktualisierungen zu einem falschen Wert für Zeile2. Dies liegt daran, dass in Java alle Instanzvariablen in der Address-Klasse beim Instanziieren einer Klasse auf null (oder Standardanfangswerte, wenn es sich um Grundelemente handelt) initialisiert werden. Es gibt also keine Möglichkeit zu unterscheiden, ob Zeile2 vom Standardwert in Null geändert wird.

Frage 1) Gibt es eine Standardmethode, um dies zu umgehen?

Ein weiterer Nachteil ist, dass ich @Valid annotation nicht verwenden kann, um die Anforderung am Einstiegspunkt zu validieren - da es sich nur um einen Teil handelt. Es könnten also ungültige Daten in das System gelangen.

Stellen Sie sich zum Beispiel vor, es gäbe ein zusätzliches Feld mit der folgenden Definition:

@Min(0) 
@Max(100)
private Integer lengthOfResidencyInYears, 

Und der Benutzer hat versehentlich 190 (als er wirklich 19 Jahre bedeutete) eingegeben, es würde nicht scheitern.

Anstelle von PATCH müsste der Client, wenn ich PUT verwendet hätte, das vollständige Adressobjekt senden. Dies hat den Vorteil, dass ich mit @Valid sicherstellen kann, dass die Adresse tatsächlich gültig ist

Wenn man davon ausgeht, dass ein GET immer durchgeführt werden muss, bevor Updates durchgeführt werden, warum sollte man dann nicht PUT over PATCH verwenden? Vermisse ich etwas?

Beiseit

Mein Fazit ist, dass Entwickler, die dynamisch typisierte Sprachen verwenden, die Befürworter der Verwendung von PATCH sind, da ich keinen Nutzen daraus ziehen kann, wenn sie in einer statisch typisierten Sprachzeile Java oder C # verwendet werden. Es scheint nur mehr Komplexität hinzuzufügen.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage