Springで入力チェック付きREST APIを作成しよう!初心者でもわかるバリデーションの基本
新人
「SpringでREST APIを作っているんですが、入力された値のチェックってどうやるんですか?」
先輩
「Springにはバリデーションという機能があって、簡単に入力チェックを組み込むことができるんだ。」
新人
「REST APIでバリデーションってどんな場面で必要なんですか?」
先輩
「それじゃあ、まず入力チェックの基本から順番に説明していくね。」
1. 入力チェック(バリデーション)とは?
Springでは、REST APIの開発において「入力チェック」や「バリデーション」は非常に重要です。バリデーションとは、ユーザーから送信されたデータが「正しい形式」や「必要な条件」を満たしているかどうかを確認する処理のことです。
例えば、名前の入力が空欄だったり、メールアドレスの形式が正しくなかったりすると、そのまま処理を進めるとシステムの不具合やバグの原因になります。そのため、APIの入り口である@Controllerクラス内でしっかりと入力内容をチェックすることが推奨されます。
Springでは、javax.validationやjakarta.validationのアノテーションを使って、非常に簡単に入力チェックを組み込むことができます。代表的なアノテーションとしては以下のようなものがあります:
@NotNull:nullでないことをチェック@Size(min = 1, max = 20):文字列の長さをチェック@Email:正しいメール形式かをチェック@Min/@Max:数値の範囲をチェック
このようなアノテーションを使うことで、初心者でも簡単に安全なAPIを作ることが可能になります。
2. REST APIにおいてバリデーションが必要な理由
REST APIでは、クライアントからのリクエストによってサーバ側の処理が行われます。もし、入力された内容に不備がある状態で処理が進行してしまうと、データベースに不正なデータが登録されたり、例外が発生したりして、システムの信頼性が下がってしまいます。
特に、フォームの送信や外部連携など、APIにさまざまな入力が届く場面では、サーバ側で入力チェックを行うことが必須です。Springのバリデーション機能を使えば、@Controllerで簡単に入力の整合性をチェックできます。
以下は、名前と年齢を受け取る簡単なリクエストDTOクラスの例です。SpringではこのようなDTOにアノテーションをつけることで、入力チェックを実現します。
package com.example.demo.dto;
import jakarta.validation.constraints.*;
public class UserRequest {
@NotBlank(message = "名前は必須です")
@Size(max = 20, message = "名前は20文字以内で入力してください")
private String name;
@NotNull(message = "年齢は必須です")
@Min(value = 0, message = "年齢は0以上を入力してください")
@Max(value = 120, message = "年齢は120以下で入力してください")
private Integer age;
// ゲッターとセッター
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
このようにして、入力される値に対して厳密な制限を設けることで、APIの品質を保つことができます。また、バリデーションに失敗したときには自動的にエラーメッセージを返すこともできるため、開発効率も向上します。
さらに、REST APIの入り口で入力エラーを検知できれば、データベースやビジネスロジックへの無駄なアクセスを減らすことができ、パフォーマンスの向上やセキュリティ強化にもつながります。
3. Springでバリデーションを行うための準備
Springでバリデーションを行うには、まず必要な依存関係がプロジェクトに追加されていることを確認する必要があります。pleiades環境では、プロジェクト作成時に「Spring Web」や「Validation」などの依存関係をチェックすることで、自動的に必要なライブラリが組み込まれます。
Gradleで手動で追加する場合は、build.gradleファイルに以下のような設定を行います:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
spring-boot-starter-validationには、バリデーションに必要なjakarta.validationパッケージが含まれています。これにより、@NotNullや@Sizeなどのアノテーションを使用できるようになります。
アノテーションはDTO(データ転送オブジェクト)に付けて使用します。代表的なアノテーションは以下のとおりです:
- @NotNull:nullでないことをチェック
- @NotBlank:nullや空文字でないことをチェック
- @Size:文字列の長さを制限
- @Min / @Max:数値の最小値・最大値を制限
- @Email:メール形式であることをチェック
このように、必要なライブラリとアノテーションの基本を理解しておくことで、Springアプリケーションに簡単に入力チェックの仕組みを導入できます。
4. @Controllerと@ResponseBodyを使ったバリデーション付きAPIの実装
それでは、実際に@Controllerと@ResponseBodyを使って、バリデーション付きのREST APIを作成してみましょう。入力内容に問題がある場合には、エラーメッセージをレスポンスとして返すように実装します。
まずは、前章でも紹介したUserRequestクラスを使って、バリデーションを行います。そして次に、@Controllerクラスを作成し、POSTリクエストを処理するメソッドに@Validを付与して、バリデーションを有効にします。
package com.example.demo.controller;
import com.example.demo.dto.UserRequest;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@Controller
public class UserController {
@ResponseBody
@PostMapping("/api/user")
public Map<String, Object> createUser(@Valid @RequestBody UserRequest request, BindingResult result) {
Map<String, Object> response = new HashMap<>();
if (result.hasErrors()) {
response.put("success", false);
response.put("errors", result.getAllErrors());
return response;
}
response.put("success", true);
response.put("message", "ユーザー情報が正常に受け取られました");
return response;
}
}
@Validを付けることで、Springが自動的にDTOのバリデーションを実行してくれます。BindingResultにはバリデーション結果が格納され、エラーがある場合はレスポンスにエラーメッセージを含めて返します。
このように@Controllerと@ResponseBodyを組み合わせることで、REST APIとして入力チェック付きの処理が実現できます。なお、@RestControllerは今回の記事では使用しないようにしています。
動作確認を行う際には、curlなどのツールを使ってPOSTリクエストを送ることで、バリデーションの結果を確認できます。以下は、nameフィールドが空の場合のレスポンス例です:
{
"success": false,
"errors": [
{
"codes": [...],
"defaultMessage": "名前は必須です",
...
}
]
}
このように、入力内容が条件を満たさない場合には、エラーメッセージがJSON形式で返されるため、クライアント側でも扱いやすい仕様となります。
Springでは、複雑な入力チェック処理もアノテーションを使うだけで簡単に実装できるため、セキュアで堅牢なREST APIを作成するうえで非常に便利です。
5. バリデーション失敗時のエラーメッセージの返し方(BindingResultの使い方)
Springのバリデーション機能では、@Validアノテーションによって入力チェックが実行され、問題がある場合はBindingResultにその結果が格納されます。初心者の方がつまずきやすいポイントとして、エラーが発生しても正しくレスポンスに表示されないということがありますが、これはBindingResultの使い方を理解することで解決できます。
以下のコードでは、エラーがある場合にフィールドごとのメッセージをMapに詰めて返却する方法を紹介します:
@ResponseBody
@PostMapping("/api/user/detail")
public Map<String, Object> validateUser(@Valid @RequestBody UserRequest request, BindingResult result) {
Map<String, Object> response = new HashMap<>();
if (result.hasErrors()) {
Map<String, String> errors = new HashMap<>();
result.getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
response.put("success", false);
response.put("errors", errors);
return response;
}
response.put("success", true);
response.put("message", "入力チェックを通過しました");
return response;
}
このようにすることで、バリデーションエラーが発生した場合にも、どの項目にどのような問題があるのかが明確にレスポンスに含まれるようになります。
例えば、nameが空でageがマイナス値だった場合のレスポンスは次のようになります:
{
"success": false,
"errors": {
"name": "名前は必須です",
"age": "年齢は0以上を入力してください"
}
}
この形式なら、フロントエンド側でユーザーにわかりやすい形でエラー表示ができるため、実用的で使いやすいAPI設計になります。
6. よくあるエラーとその対処法
Springで入力チェックを導入する際、初心者がよく直面するエラーにはいくつかの共通点があります。ここではその代表的なものと解決方法を紹介します。
(1)@Validを付け忘れている
バリデーションが機能しない原因の多くは、@Validアノテーションを忘れているケースです。DTOにアノテーションをつけただけではチェックは行われず、必ずコントローラのメソッド引数に@Validを付与する必要があります。
// 必須!@Validを忘れずに!
public Map<String, Object> create(@Valid @RequestBody UserRequest request, BindingResult result)
(2)BindingResultの順番を間違えている
BindingResultは、必ず@Valid付き引数の直後に置く必要があります。順番が違うと、バリデーションエラーが正しく処理されません。
// 正しい順番
(@Valid @RequestBody UserRequest request, BindingResult result)
(3)エラーが返らない・例外になる
上記2点が守られていないと、エラーレスポンスが返らずにMethodArgumentNotValidExceptionがスローされてしまう場合があります。例外が起きると500エラーになり、クライアントは正確なエラー情報を取得できません。これを防ぐには、@ValidとBindingResultの使い方を正しく実装することが重要です。
7. curlでバリデーションをテストしてみよう
作成したバリデーション付きのREST APIは、curlコマンドを使って簡単に動作確認できます。curlはコマンドラインでHTTPリクエストを送信できるツールで、リクエストボディのJSONデータを指定してPOSTすることが可能です。
(1)正常なリクエスト例
まずはバリデーションを通過する正しい入力の例です:
curl -X POST http://localhost:8080/api/user \
-H "Content-Type: application/json" \
-d '{"name": "山田太郎", "age": 30}'
{
"success": true,
"message": "ユーザー情報が正常に受け取られました"
}
(2)バリデーションエラーが発生するリクエスト
次に、nameが空、ageがマイナスの不正な入力例です:
curl -X POST http://localhost:8080/api/user \
-H "Content-Type: application/json" \
-d '{"name": "", "age": -5}'
{
"success": false,
"errors": {
"name": "名前は必須です",
"age": "年齢は0以上を入力してください"
}
}
このように、curlを使うことで、ブラウザやフロントエンドを準備せずに、APIの動作確認や入力チェックのテストができます。初心者にとっても手軽に実践できる方法なので、積極的に活用しましょう。