こんにちは!今回は、Spring Frameworkで部分的なデータ更新に使用されるアノテーション、@PatchMappingについて詳しく解説します。@PatchMappingを使えば、特定のフィールドだけを更新するリクエストを簡単に処理できるようになります。
@PatchMappingとは?
@PatchMappingとは、
「既存データの一部だけを更新するためのアノテーション」
のことです。
たとえば、ユーザーのメールアドレスだけを更新したい場合、@PatchMappingを使うことで、他のフィールドに変更を加えずにメールアドレスだけを更新できます。
部分的な更新を行うことは、パフォーマンスや柔軟性の面でとても大事なことです。
特に大規模なオブジェクトを扱う際、全フィールドを送信せずに必要な部分だけ変更することで、通信コストを削減できます。
PATCHリクエストはAPIクライアントツール(たとえばPostman)やJavaScriptのfetch APIを使って送信するのが一般的です。
基本的な使い方
まずは、簡単なコード例を見てみましょう。ユーザー情報のうち、メールアドレスだけを更新するケースを紹介します。
サーバー側のコード
@PatchMapping("/users/{id}")
public User updateUserEmail(@PathVariable Long id, @RequestBody Map<String, Object> updates) {
User user = userService.getUserById(id);
if (updates.containsKey("email")) {
user.setEmail((String) updates.get("email"));
}
return userService.saveUser(user);
}
このコードでは、特定のユーザーIDに対して送信されたPATCHリクエストに基づき、ユーザーのメールアドレスだけを更新します。@RequestBody
で受け取るデータはMap型にしておき、更新したいフィールド(この場合はemail
)だけを抜き出して処理しています。
クライアント側のコード
const updates = { email: "new-email@example.com" };
fetch(`http://localhost:8080/users/1`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
});
クライアント側では、PATCHリクエストを送信してユーザーのメールアドレスを更新しています。APIクライアントやJavaScriptのフロントエンドから簡単にリクエストを投げることが可能です。
@PatchMappingの使い方【応用編】
@PatchMappingを使った部分的な更新は、より複雑なシナリオでも便利です。ここでは、少し高度な使い方を見ていきましょう。
1. URLパス内の変数を使う
@PatchMappingでは、URLパスに動的な値(パス変数)を組み込むことができます。例えば、特定の商品情報を部分的に更新したい場合を考えてみましょう。
@PatchMapping("/products/{id}")
public ResponseEntity<Product> updateProductDetails(@PathVariable Long id, @RequestBody Map<String, Object> updates) {
Product product = productService.getProductById(id);
updates.forEach((key, value) -> {
switch (key) {
case "name":
product.setName((String) value);
break;
case "price":
product.setPrice((Double) value);
break;
// 他のフィールドも同様に処理可能
}
});
return ResponseEntity.ok(productService.saveProduct(product));
}
この例では、商品IDに基づいて送信されたリクエストボディからフィールドを抽出し、商品情報を部分的に更新しています。
2. DTOを使ったバリデーション
更新するデータにバリデーションが必要な場合、@Validアノテーションを使ってデータを検証できます。
@PatchMapping("/users/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @Valid @RequestBody UserDto updates, BindingResult result) {
if (result.hasErrors()) {
return ResponseEntity.badRequest().build();
}
User user = userService.updateUserDetails(id, updates);
return ResponseEntity.ok(user);
}
このコードでは、DTOを使って部分的な更新を行い、@Validでデータの整合性を検証しています。エラーがある場合は、400 Bad Requestを返します。
3. JSON Patchのサポート
部分的な更新には、RFC 6902で定義されているJSON Patchを使う方法もあります。これにより、複雑なオブジェクトの更新操作を簡素化できます。
@PatchMapping(path = "/users/{id}", consumes = "application/json-patch+json")
public ResponseEntity<User> patchUser(@PathVariable Long id, @RequestBody JsonPatch patch) {
User user = userService.getUserById(id);
User patchedUser = userService.applyPatchToUser(patch, user);
return ResponseEntity.ok(patchedUser);
}
この例では、application/json-patch+json
という特定のメディアタイプを消費し、PATCH操作を柔軟に行います。
4. クエリパラメータを使った部分更新
クエリパラメータを使うことで、PATCHリクエストをさらに柔軟に制御できます。
@PatchMapping("/users/{id}")
public ResponseEntity<User> updateUserWithParams(@PathVariable Long id,
@RequestParam("email") String newEmail) {
User user = userService.getUserById(id);
user.setEmail(newEmail);
return ResponseEntity.ok(userService.saveUser(user));
}
この例では、クエリパラメータを使用してメールアドレスだけを更新します。
5. HTTPヘッダーを使った更新処理
リクエストヘッダーを使用して認証や特定の条件を設定することが可能です。
@PatchMapping("/users/{id}")
public ResponseEntity<User> updateUserWithHeader(@PathVariable Long id,
@RequestBody User updates,
@RequestHeader("Authorization") String token) {
if (!authService.isValidToken(token)) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
return ResponseEntity.ok(userService.updateUser(id, updates));
}
この例では、リクエストヘッダーから認証トークンを取得し、認証が成功した場合にのみデータを更新します。
@PatchMappingの引数
@PatchMappingでは、さまざまな引数を使ってリクエスト処理を細かく制御できます。
1. value属性
value
属性で、どのURLに対してメソッドが応答するかを指定します。
@PatchMapping(value = "/users/{id}")
public ResponseEntity<User> patchUser(@PathVariable Long id, @RequestBody Map<String, Object> updates) {
return ResponseEntity.ok(userService.updateUserDetails(id, updates));
}
2. consumes属性
consumes
属性を使って、特定のメディアタイプを指定できます。
@PatchMapping(value = "/users/{id}", consumes = "application/json")
public ResponseEntity<User> patchUserJson(@PathVariable Long id, @RequestBody User updates) {
return ResponseEntity.ok(userService.updateUser(id, updates));
}
3. produces属性
produces
属性を使って、レスポンスのメディアタイプを指定できます。
@PatchMapping(value = "/users/{id}", produces = "application/json")
@ResponseBody
public User patchUserAndReturnJson(@PathVariable Long id, @RequestBody User updates) {
return userService.updateUser(id, updates);
}
おわりに
@PatchMappingを使えば、部分的なデータ更新を簡単に実装できます。REST API開発においては、@PutMappingと同様に非常に重要な存在です。今回は基本的な使い方から応用例まで紹介しましたので、実際にコードを書いて試してみてください!
もっと詳しく知りたい方は、Spring公式ドキュメントを見てみてくださいね。
他のMappingについて知りたい方はこちらをどうぞ!