はじめに
最近、SpringBootについて学んでいます。今回はリクエスト、レスポンスをJSONで扱う方法を整理します。
今回の想定
今回は以下の機能を題材にしてみます。
- request
- firstNum,secondNumを引数で受け取る
- response
- 足した結果をresultに設定して返す
controllerの実装
まずは実装例から。
それぞれ整理していきましょう。
@RestController
public class CalculationController {
@PostMapping("/calculate")
public CalculationResponse calculate(@RequestBody CalculationRequest request) {
// レスポンスオブジェクトを作成
CalculationResponse response = new CalculationResponse();
// 計算処理
int result = request.getFirstNum() + request.getSecondNum();
// 結果を設定
response.setResult(result);
return response;
}
}
RestController
RESTの場合は、@RestController
を使用します。@Controller
もありますが、こちらはMVCなどで、テンプレート(HTML)を返す場合に使用します。
このアノテーションによって、該当のコントーラーがRESTであることを定義します。
RequestBody
POSTなどで受け取った情報をクラスと紐付けるために使用します。
@RequestBody CalculationRequest request
で、Bodyの内容がCalculationRequestに変換されます
CalculationRequest / CalculationResponse
CalculationRequest
リクエストで受け取るクラスを定義します。
public class CalculationRequest {
private int firstNum;
private int secondNum;
// getter, setter
public int getFirstNum() {
return firstNum;
}
public void setFirstNum(int firstNum) {
this.firstNum = firstNum;
}
public int getSecondNum() {
return secondNum;
}
public void setSecondNum(int secondNum) {
this.secondNum = secondNum;
}
}
CalculationResponse
レスポンスのクラスを定義します。
public class CalculationResponse {
private int result;
// getter, setter
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
}
実際のAPIの動き
実装したAPIの動作を確認してみましょう。以下にcurlコマンドを使用したリクエスト例と、それに対するレスポンスを示します。
curl -X POST http://localhost:8080/calculate \
-H "Content-Type: application/json" \
-d '{
"firstNum": 10,
"secondNum": 20
}'
- リクエスト例
{
"firstNum": 10,
"secondNum": 20
}
- レスポンス例
{
"result": 30
}
リクエストのJSONとクラスの関係
なんとなく伝わったかもしれませんが、@RequestBody
で指定したクラスにJSONが変換されています。
クラスとJSONの比較
JSONのキーとクラスのフィールド名が一致する場合、自動的にマッピングされます。
public class CalculationRequest {
private int firstNum; // ← JSONの"firstNum"と一致
private int secondNum; // ← JSONの"secondNum"と一致
}
{
"firstNum": 10, // ← クラスのfirstNumフィールドにマッピング
"secondNum": 20 // ← クラスのsecondNumフィールドにマッピング
}
マッピングされない例
以下のような場合、正しくマッピングされません。
- フィールド名が異なる場合
public class CalculationRequest {
private int first; // "firstNum"とは異なる名前
private int second; // "secondNum"とは異なる名前
}
{
"firstNum": 10, // マッピングされない
"secondNum": 20 // マッピングされない
}
- データ型が一致しない場合
public class CalculationRequest {
private String firstNum; // 文字列型で定義
private int secondNum; // 数値型で定義
}
{
"firstNum": 10, // 数値型のため、String型へのマッピングでエラー
"secondNum": "20" // 文字列型のため、int型へのマッピングでエラー
}
これらの場合は、400 Bad Reqest
が発生します。
いろいろなパターンの実装例
JSONのフィールドにオブジェクト
オブジェクトをネストすることもできます。
public class UserRequest {
private String name;
private Address address; // オブジェクトをネスト
// Address クラス
public static class Address {
private String city;
private String street;
// getter, setter
}
// getter, setter
}
{
"name": "John",
"address": {
"city": "Tokyo",
"street": "Shibuya 1-1-1"
}
}
配列
配列やリストも扱えます。
public class BatchCalculationRequest {
private List<Integer> numbers; // 数値の配列
private List<User> users; // オブジェクトの配列
// User クラス
public static class User {
private String name;
private int age;
// getter, setter
}
// getter, setter
}
{
"numbers": [1, 2, 3, 4, 5],
"users": [
{"name": "John", "age": 30},
{"name": "Jane", "age": 25}
]
}
バリデーション
バリデーションをすることも可能です。独自実装も可能ですが。こちらもフレームワークにお任せしましょう。
- 必要な依存関係の導入
- それぞれの環境に合わせて
spring-boot-starter-validation
を導入します。
- それぞれの環境に合わせて
そして、 controllerで@Valid
を使用して、バリデーションを有効化します。
@RestController
public class CalculationController {
@PostMapping("/calculate")
public CalculationResponse calculate(@Valid @RequestBody CalculationRequest request) {
// バリデーションエラーの場合、自動的に400エラーが返される
// ...
}
}
では、それぞれのクラスでバリデーションを実装してみます。
文字列長チェック
public class UserRequest {
@NotNull(message = "名前は必須です")
@Size(min = 1, max = 50, message = "名前は1~50文字で入力してください")
private String name;
@Email(message = "メールアドレスの形式が不正です")
private String email;
// getter, setter
}
数値チェック
public class CalculationRequest {
@Min(value = 0, message = "0以上の値を入力してください")
@Max(value = 100, message = "100以下の値を入力してください")
private int firstNum;
@Positive(message = "正の値を入力してください")
private int secondNum;
// getter, setter
}
他にもいろいろあります。独自のルールでバリデーションを実装することも可能です。
まとめ
とても基本的なAPIの流れとして、JSONでリクエストを受けて、JSONのレスポンスを返す方法をまとめました。また、バリデーションの実装方法もみてみました。
すごく基本的ですが、API開発で最初に必要になる部分です。
少しでも参考に、とっかかりのハードルが低くなれば幸いです。