1概要

このクイック記事では、HTTP PUT動詞とPATCH動詞の違いと、2つの操作の意味について説明します。

Springを使用して、これら2種類の操作をサポートする2つのRESTエンドポイントを実装し、違いとそれらを使用する正しい方法をよく理解します。

** 2 PUTとWhen PATCHを使用する場合

単純な、そして少し単純なステートメントから始めましょう。

  • クライアントが既存のリソースを完全に置き換える必要がある場合は、PUTを使用できます。部分的な更新をしているときは、HTTP PATCHを使用できます。

例えば、リソースの単一のフィールドを更新するとき、完全なリソース表現を送信することは面倒であり、多くの不必要な帯域幅を利用するかもしれません。そのような場合、PATCHの意味論はもっと理にかなっています。

ここで考慮すべきもう1つの重要な側面は

冪等です。 PUTはべき等です。 PATCHは可能ですが、必須ではありません

。そのため、実装している操作のセマンティクスに応じて、この特性に基づいてどちらかを選択することもできます。


3 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

全体を送信するというオーバーヘッドなしに、更新する必要のあるフィールドだけを送信できます。

これらの部分更新操作が多数ある場合は、それぞれのoutに対してカスタム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の実装における柔軟性が向上します。ただし、検証など、いくつかのことも失います。


4 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());


5

Null

値を使用した部分的な要求の処理

PATCHメソッドの実装を書くときは、

HeavyResourceAddressOnly.



address

フィールドの値として

null

を取得したときのケースの扱い方の規約を指定する必要があります。

クライアントが次の要求を送信したとします。

{
   "id" : 1,
   "address" : null
}

それから、

address

フィールドの値を

null

に設定するか、そのような要求を変更なしとして扱うことで無視するだけで処理できます。

私たちは

null

を扱うための一つの戦略を選び、あらゆるPATCHメソッドの実装でそれに固執するべきです。


6. 結論

このクイックチュートリアルでは、HTTP PATCHとPUTメソッドの違いを理解することに焦点を当てました。

PUTメソッドを使用してリソースを更新するための単純なSpring RESTコントローラーと、PATCHを使用した部分的な更新を実装しました。

これらすべての例とコードスニペットの実装はhttps://github.com/eugenp/tutorials/tree/master/spring-rest[GitHubプロジェクト]で見つけることができます – これはMavenプロジェクトです。そのままインポートして実行します。