私はJavaの新しい残りのAPIで開発を開始しようとしています。 私の質問は、パッチの使用についてです - なぜですか?Java REST APIで、PATCHとPUTを使用してエンティティを更新する
次のリクエストでPOST http://localhost:8080/addresses
:
は、我々は新しいアドレスを作成するには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;
}
という名前のエンティティを持っている、と言うことができます、私は、このHTTPリクエストを行うだろう
{
"line1" : "mandatory Address line 1",
"line2" : "optional Address line 2",
"city" : "mandatory City",
"state" : "cd"
}
作成されたレコードのIDが1であると仮定します。
対応@RestController AddressResource.javaは、この方法を有することになる。
@PostMapping(value = "/addresses")
public ResponseEntity<Address> create(@valid Address newAddress) {
addressRepo.save(newAddress);
}
@Validは、エンティティテーブルにデータを格納する前に有効であることを確認します。
ここで、私は上のアパートから通りの家に移動します。私はPATCHを使用する場合は、要求ペイロードと
PATCH http://localhost:8080/addresses/1
次のようになります。
{
"line1" : "1234 NewAddressDownTheStreet ST",
"line2" : null
}
@RestController対応する方法は次のようになります。あなたがテーブルを照会すると
@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)
}
は今、」勝ちました私の住所は?
"line1" : "1234 NewAddressDownTheStreet ST",
"line2" : "optional Address line 2", <-- INCORRECT. Should be null.
"city" : "mandatory City",
"state" : "cd"
上記の更新によって、line2の値が正しくないことがわかります。 これは、Javaでは、Addressクラスのすべてのインスタンス変数が、クラスがインスタンス化されるときにnull(またはプリミティブの場合はデフォルトの初期値)に初期化されるためです。したがって、nullに変更されるline2とデフォルト値を区別する方法はありません。
質問1)これを回避する標準的な方法はありますか?
もう一つの欠点は、私がエントリポイントで要求を検証するために@Validアノテーションを使用することができない、ということである - それは一部だけですだって。したがって、無効なデータがシステムに入る可能性があります。 、それは失敗しないだろう
@Min(0)
@Max(100)
private Integer lengthOfResidencyInYears,
を、ユーザーが誤って(彼らは本当に19年を意味したときに)190を入力:
例えば、追加のフィールドは、次のように定義していたと想像。
PATCHではなく、PUTを使用した場合、クライアントは完全なアドレスオブジェクトを送信する必要があります。 は、これは私が1のGETが常に更新を行う前に、なぜだろうではない1回の使用PUTを行わなければならないという前提を作る場合はアドレスが実際に
有効であることを確認するために@Validを使用できるという利点を有しますオーバーパッチ? 何か不足していますか?
別に
私の結論は、私は静的型付け言語のラインJavaやC#からそれを使用するすべての利点を見ることができないように動的型付け言語を使用して、開発者がパッチを使用しての支持者であるということです。それはちょうど複雑さを加えるようです。
は、PATCHリクエスト後に、dbAddress.getLine2()!= nullをチェックしているため、dbクエリで行「省略可能なアドレス行2」を表示する必要があります。 – kuhajeyan
パッチ要求には、サーバーが一部のリソースの状態Aを状態Bに変換するために使用できるクライアントによって計算された命令が含まれている必要があり、単純化された部分的な更新ではありません。さらに読む:[SOドキュメント](http://stackoverflow.com/documentation/http/3423/http-for-apis/11812/edit-a-resource#t=201610031245323472567)と[良いブログ投稿](http: /williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/) –
これは良い質問です。 line2のnullについては、手動でフィールドをマップし、上書きするためにnull以外の値をチェックするためです。現在私は[Dozer](http://dozer.sourceforge.net/documentation/usage.html)を使用するプロジェクトに取り組んでおり、nullをマップすることを選択できます。とにかくPOSTを使ってリソースを追加/作成し、PUTを使ってそれらを修正しますが、このマッパーでは部分的なマッピングを行うことができます。だから私はこれが好ましい方法であるか、POST(作成)、PUT(完全更新)、PATCH(部分更新)を使用すべきかどうかについて議論しています。 –