概要
このクイック記事では、HTTP putとPATCHの動詞の違いと、2つの操作のセマンティクスについて見ています。
Springを使用して、これら二つのタイプの操作をサポートする二つのRESTエンドポイントを実装し、違いとそれらを使用する正しい方法をよりよく理解
いつPutとWhen Patchを使用するのですか?
シンプルで、少し単純な文から始めましょう。
クライアントが既存のリソースを完全に置き換える必要がある場合、PUTを使用できます。 彼らが部分的な更新をしているとき、彼らはHTTP PATCHを使うことができます。
たとえば、リソースの単一のフィールドを更新する場合、完全なリソース表現を送信するのは面倒であり、不要な帯域幅を多く利用する可能性があります。 そのような場合、PATCHのセマンティクスはより多くの意味を持ちます。
ここで考慮すべきもう一つの重要な側面は冪等です。PUTは冪等です。PATCHは可能ですが、必須ではありません。 そして、私たちが実装している操作のセマンティクスに応じて、この特性に基づいてどちらか一方を選択することもできます。
PUTおよびPATCHロジックの実装
複数のフィールドを持つHeavyResourceを更新するためのREST APIを実装したいとしましょう:
public class HeavyResource { private Integer id; private String name; private String address; // ...
まず、putを使用してリソースの完全な更新を処理するエンドポイントを作成する必要があります:
@PutMapping("/heavyresource/{id}")public ResponseEntity<?> saveResource(@RequestBody HeavyResource heavyResource, @PathVariable("id") String id) { heavyResourceRepository.save(heavyResource, id); return ResponseEntity.ok("resource saved");}
これは、リソースを更新するための標準エンドポイントです。
さて、アドレスフィールドはクライアントによって頻繁に更新されるとしましょう。 その場合、すべてのフィールドを含むHeavyResourceオブジェクト全体を送信するのではなく、patchメソッドを介してaddressフィールドのみを更新する機能が必要です。
アドレスフィールドの部分的な更新を表すHeavyResourceAddressOnly DTOを作成できます:
public class HeavyResourceAddressOnly { private Integer id; private String address; // ...}
次に、PATCHメソッドを利用して部分的な更新を送信できます:
@PatchMapping("/heavyresource/{id}")public ResponseEntity<?> partialUpdateName( @RequestBody HeavyResourceAddressOnly partialUpdate, @PathVariable("id") String id) { heavyResourceRepository.save(partialUpdate, id); return ResponseEntity.ok("resource address updated");}
このより詳細なDTOを使用すると、HeavyResource全体を送信するオーバーヘッドなしで、更新する必要があるフィールドのみを送信できます。
これらの部分的な更新操作が多数ある場合は、各アウトのカスタムDTOの作成をスキップして、マップのみを使用することもできます:
@RequestMapping(value = "/heavyresource/{id}", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE)public ResponseEntity<?> partialUpdateGeneric( @RequestBody Map<String, Object> updates, @PathVariable("id") String id) { heavyResourceRepository.save(updates, id); return ResponseEntity.ok("resource updated");}
このソリューションは、APIを実装する際の柔軟性を向上させますが、検証などのいくつかのことも失います。
PUTとPATCHのテスト
最後に、両方のHTTPメソッドのテストを書いてみましょう。 まず、PUTメソッドを使用して完全なリソースの更新をテストしたいと考えています:
mockMvc.perform(put("/heavyresource/1") .contentType(MediaType.APPLICATION_JSON_VALUE) .content(objectMapper.writeValueAsString( new HeavyResource(1, "Tom", "Jackson", 12, "heaven street"))) ).andExpect(status().isOk());
部分的な更新の実行は、PATCHメソッドを使用して実現されます:
mockMvc.perform(patch("/heavyrecource/1") .contentType(MediaType.APPLICATION_JSON_VALUE) .content(objectMapper.writeValueAsString( new HeavyResourceAddressOnly(1, "5th avenue"))) ).andExpect(status().isOk());
より一般的なアプローチのためのテストを書くこともできます:
HashMap<String, Object> updates = new HashMap<>();updates.put("address", "5th avenue");mockMvc.perform(patch("/heavyresource/1") .contentType(MediaType.APPLICATION_JSON_VALUE) .content(objectMapper.writeValueAsString(updates)) ).andExpect(status().isOk());
Null値を持つ部分的な要求の処理
PATCHメソッドの実装を作成しているとき、HeavyResourceAddressOnlyのaddressフィールドの値としてnullを取得した場合の処理方法のコントラクトを指定する必要があります。
クライアントが次の要求を送信したとします:
{ "id" : 1, "address" : null}
次に、これをアドレスフィールドの値をnullに設定するか、変更なしとして扱うことによってそのような要求を無視するように処理できます。
nullを処理するための戦略を1つ選択し、すべてのPATCHメソッドの実装でそれに固執する必要があります。
結論
このクイックチュートリアルでは、HTTP PATCHメソッドとPUTメソッドの違いを理解することに焦点を当てました。
Putメソッドを使用してリソースを更新し、PATCHを使用して部分的な更新を行う単純なSpring RESTコントローラを実装しました。
これらすべての例とコードスニペットの実装はGitHubプロジェクトで見つけることができます–これはMavenプロジェクトなので、そのままインポートして実
Learn Springコースを通じて、Spring5とSpring Boot2を使い始めましょう:
>> コースをチェックしてください