前回は GET で JSON データを返す API を作りました。Web アプリでは読み取りだけでなく、データの作成・更新・削除も必要です。それぞれの操作に対応する HTTP メソッドがあります。
HTTP メソッドと CRUD の対応
DB の回で SQL の CRUD を学びました。REST API でも同じ4操作を HTTP メソッドで表現します。
| 操作 | SQL | HTTP メソッド | Spring Boot のアノテーション |
|---|---|---|---|
| 作成 | INSERT | POST | @PostMapping |
| 読み取り | SELECT | GET | @GetMapping |
| 更新 | UPDATE | PUT | @PutMapping |
| 削除 | DELETE | DELETE | @DeleteMapping |
前回は GET(読み取り)だけを扱いました。今回は残りの3つを追加します。
仮のデータストアを用意する
データベースとの接続は次回に回します。今回は ArrayList を使い、メモリ上でデータを管理します。
EmployeeController.java を次のように書き換えます。
package com.example.demo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.*;
@RestController
@CrossOrigin
public class EmployeeController {
private List<Employee> employees = new ArrayList<>();
private int nextId = 1;
public EmployeeController() {
employees.add(new Employee(nextId++, "田中太郎", "開発部"));
employees.add(new Employee(nextId++, "鈴木花子", "営業部"));
employees.add(new Employee(nextId++, "佐藤次郎", "開発部"));
}
@GetMapping("/api/employees")
public List<Employee> getAll() {
return employees;
}
}
コンストラクタで初期データを3件入れています。nextId は新しい社員を追加するとき用の連番です。
import org.springframework.web.bind.annotation.*; の * は、@GetMapping @PostMapping @RequestBody などをまとめてインポートする書き方です。
POST で追加する
新しい社員を追加する API を作ります。getAll メソッドの下に追加します。
@PostMapping("/api/employees")
public Employee create(@RequestBody Employee employee) {
Employee newEmployee = new Employee(nextId++, employee.getName(), employee.getDepartment());
employees.add(newEmployee);
return newEmployee;
}
新しいアノテーションが2つ出てきます。
| アノテーション | 役割 |
|---|---|
@PostMapping | POST リクエストを受け取るメソッドに付ける |
@RequestBody | リクエストの JSON を Java オブジェクトに変換する |
クライアントが送る JSON はこのような形です。
{"name": "山田美咲", "department": "総務部"}
@RequestBody が付いた引数に、Jackson が JSON → Employee オブジェクトの変換を行います。GET のときは Java → JSON でしたが、今度は逆方向の JSON → Java です。
id はサーバー側で nextId++ を使って採番するため、クライアントからは送りません。Employee クラスに id を受け取らないコンストラクタか setter が必要になります。
Employee クラスにデフォルトコンストラクタと setter を追加します。
package com.example.demo;
public class Employee {
private Integer id;
private String name;
private String department;
public Employee() {
}
public Employee(Integer id, String name, String department) {
this.id = id;
this.name = name;
this.department = department;
}
public Integer getId() { return id; }
public String getName() { return name; }
public String getDepartment() { return department; }
public void setId(Integer id) { this.id = id; }
public void setName(String name) { this.name = name; }
public void setDepartment(String department) { this.department = department; }
}
引数なしの public Employee() {} は Jackson がオブジェクトを作るために必要です。setter は JSON の値をフィールドに入れるために使われます。
PUT で更新する
EmployeeController.java に、create メソッドの下へ追加します。ID を指定して社員情報を更新する API です。
@PutMapping("/api/employees/{id}")
public Employee update(@PathVariable int id, @RequestBody Employee employee) {
for (Employee e : employees) {
if (e.getId() == id) {
e.setName(employee.getName());
e.setDepartment(employee.getDepartment());
return e;
}
}
return null;
}
@PathVariable は URL の {id} 部分を引数として受け取る仕組みです。/api/employees/2 にアクセスすると id に 2 が入ります。
処理の流れをたどります。
- URL の
{id}で対象を特定する - リクエストの JSON からname と department を取得する
- リスト内で一致する Employee を探して値を更新する
- 更新後の Employee を返す
DELETE で削除する
同じく EmployeeController.java に update メソッドの下へ追加します。
@DeleteMapping("/api/employees/{id}")
public String delete(@PathVariable int id) {
employees.removeIf(e -> e.getId() == id);
return "deleted";
}
removeIf は、条件に一致する要素をリストから取り除くメソッドです。e -> e.getId() == id はラムダ式と呼ばれる書き方で、「各要素 e について e.getId() == id が true なら削除する」という意味です。
ラムダ式は Java 8 で追加された機能で、「処理を短く書く方法」として覚えておいてください。
EmployeeController.java の完成形
ここまでの4つのメソッドをすべて追加した EmployeeController.java の全体です。
package com.example.demo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.*;
@RestController
@CrossOrigin
public class EmployeeController {
private List<Employee> employees = new ArrayList<>();
private int nextId = 1;
public EmployeeController() {
employees.add(new Employee(nextId++, "田中太郎", "開発部"));
employees.add(new Employee(nextId++, "鈴木花子", "営業部"));
employees.add(new Employee(nextId++, "佐藤次郎", "開発部"));
}
@GetMapping("/api/employees")
public List<Employee> getAll() {
return employees;
}
@PostMapping("/api/employees")
public Employee create(@RequestBody Employee employee) {
Employee newEmployee = new Employee(nextId++, employee.getName(), employee.getDepartment());
employees.add(newEmployee);
return newEmployee;
}
@PutMapping("/api/employees/{id}")
public Employee update(@PathVariable int id, @RequestBody Employee employee) {
for (Employee e : employees) {
if (e.getId() == id) {
e.setName(employee.getName());
e.setDepartment(employee.getDepartment());
return e;
}
}
return null;
}
@DeleteMapping("/api/employees/{id}")
public String delete(@PathVariable int id) {
employees.removeIf(e -> e.getId() == id);
return "deleted";
}
}
curl で動作確認する
POST / PUT / DELETE はブラウザの URL バーでは試せません。ターミナルからコマンドを使って確認します。
Spring Boot を起動した状態で、別のターミナルを開いて実行します。
一覧を確認(どちらの環境でも同じ):
curl http://localhost:8080/api/employees
新規追加(POST):
Windows(PowerShell)の場合:
Invoke-RestMethod -Uri http://localhost:8080/api/employees -Method Post -ContentType "application/json" -Body '{"name":"山田美咲","department":"総務部"}'
macOS / Linux の場合:
curl -X POST http://localhost:8080/api/employees -H "Content-Type: application/json" -d '{"name":"山田美咲","department":"総務部"}'
更新(PUT):
Windows(PowerShell)の場合:
Invoke-RestMethod -Uri http://localhost:8080/api/employees/1 -Method Put -ContentType "application/json" -Body '{"name":"田中太郎","department":"総務部"}'
macOS / Linux の場合:
curl -X PUT http://localhost:8080/api/employees/1 -H "Content-Type: application/json" -d '{"name":"田中太郎","department":"総務部"}'
削除(DELETE):
Windows(PowerShell)の場合:
Invoke-RestMethod -Uri http://localhost:8080/api/employees/1 -Method Delete
macOS / Linux の場合:
curl -X DELETE http://localhost:8080/api/employees/1
各コマンドを実行したあとに一覧取得を打って、データが変わっていることを確認します。
アプリを再起動すると、ArrayList の中身はリセットされます。データの永続化は次回、データベースを接続して実現します。
ここまでの整理
| メソッド | アノテーション | 役割 |
|---|---|---|
| GET | @GetMapping | データの取得 |
| POST | @PostMapping + @RequestBody | データの作成 |
| PUT | @PutMapping + @PathVariable + @RequestBody | データの更新 |
| DELETE | @DeleteMapping + @PathVariable | データの削除 |
次の回へ
POST で社員を追加し、PUT で更新し、DELETE で削除できることを curl で確認できたら、この回は完了です。
今のデータは再起動で消えます。次の回ではデータベースとつないで、データを永続的に保存できるようにします。