Spring Bootを使ったREST APIの基本構築から動作確認まで②

## はじめに
Spring Bootを使用して、基本的なCRUD操作ができる簡単なREST APIを構築する方法を解説していきます。
本記事では、各HTTPメソッドを使用した動作確認について説明します。
前回の記事で、使用する環境・ツールの基本構築から、簡単な動作確認について説明していますので、よければそちらもご覧ください。
[Spring Bootを使ったREST APIの基本構築から動作確認まで①](https://qiita.com/pomecode/private/dcd2353d1f3b49dc23ff)

## 対象者
・Javaの基礎知識を持っている方
・Spring Bootを初めて触る方、もしくは少し触ったことがある方
・REST APIについて学びたい方

## 動作環境
・Eclipse 2022（Pleiades All in One）
・Spring Boot 3.4.4
・Advanced REST Client

## 事前準備
本記事で使用する環境・ツールについて、インストール手順を記載していきます。
Eclipse（Pleiades All in One）、及びSpring Boot（Spring Initializr）については前回の記事で紹介していますので、そちらをご確認ください。
[Spring Bootを使ったREST APIの基本構築から動作確認まで①-事前準備](https://qiita.com/pomecode/private/dcd2353d1f3b49dc23ff#%E4%BA%8B%E5%89%8D%E6%BA%96%E5%82%99)

### Advanced REST Client
HTTPリクエストの通信やテストを行うために利用されるツールです。
HTTPリクエストを作成し、サーバーに送信したり、レスポンスを受け取って表示することもできます。
今回はREST APIの稼働を確認するために使用します。

**手順**
1. 以下より、最新版のインストールファイルをダウンロード
Windows：arc-setup.exe
Mac：arc-macos.dmg
[git-hub/Advanced REST Client](https://github.com/advanced-rest-client/arc-electron/releases)
1. ダウンロードしたファイルをクリックして起動

## APIの実装
それでは、EclipseでSpringのプロジェクトを作成し、実装していきましょう。
Spring Initializrを使用したプロジェクト作成についても前回の記事で紹介していますので、そちらをご確認ください。
[Spring Bootを使ったREST APIの基本構築から動作確認まで①-Spring Initializr](https://qiita.com/pomecode/private/dcd2353d1f3b49dc23ff#spring-initializr)

今回はプロジェクト名を"restapidemo2"として作成します。
依存性はSpring WebのみでOKです。

### model
まず、modelを実装します。
com.example.restapidemo2パッケージの配下にmodelパッケージを作成し、その中にTaskクラスを作成します。
Taskクラスは属性としてid、title、statusを持ち、それぞれのgetter、setter及びコンストラクタを定義しておきます。

```java:Task.java
package com.example.restapidemo2.model;

public class Task {
	private Long id;
	private String title;
	private String status;

	public Task() {

	}

	public Task(Long id, String title, String status) {
		this.id = id;
		this.title = title;
		this.status = status;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}
}
```

### service
続いて、serviceの実装です。
同じく、com.example.restapidemo2パッケージの配下にserviceパッケージを作成し、その中にTaskServiceクラスを作成します。
TaskServiceクラスはSpring Boot上でServiceクラスであることを明示するためにServiceアノテーションを付与します。
また、ロジックとしてタスクの全件取得、1件取得、追加、更新、削除を行う処理と、今回はDBに接続しないため、serviceクラスの中にリストとしてタスク一覧を定義しておきます。

```java:TaskService.java
package com.example.restapidemo2.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.stereotype.Service;

import com.example.restapidemo2.model.Task;

@Service
public class TaskService {
	
	private List<Task> allTasks = new ArrayList<> (Arrays.asList(
			new Task("001", "掃除", "TODO"),
			new Task("002", "洗濯", "DONE"),
			new Task("003", "勉強", "IN_PROGRESS"),
			new Task("004", "料理", "TODO"),
			new Task("005", "買い物", "DONE")));

	public List<Task> getAllTasks(){
		return allTasks;
	}
	
	public Task getTask(String id) {
		for (int i = 0; i < allTasks.size(); i++) {
			if (allTasks.get(i).getId().equals(id)) {
				return (Task)allTasks.get(i);
			}
		}
		return null;
	}
	
	public void addTask(Task task) {
		allTasks.add(task);
	}
	
	public void updateTask(String id, Task task) {
		for (int i = 0; i < allTasks.size(); i++) {
			if (allTasks.get(i).getId().equals(id)) {
				allTasks.set(i, task);
			}
		}
	}
	
	public void deleteTask(String id) {
		allTasks.removeIf(i -> i.getId().equals(id));
	}
}
```

### controller
最後に、controllerの実装です。
同様に、com.example.restapidemo2パッケージの配下にcontrollerパッケージを作成し、その中にTaskControllerクラスを作成します。
TaskControllerクラスにはREST API用のControllerクラスとして、RestControllerアノテーションを付与します。
クラスに付与することで、そのクラス内のメソッドの戻り値がHTTPのレスポンスボディとして返却されます。
また、GetMappingなどのマッピング系のアノテーションについては、クライアントのリクエストURLがエンドポイント（パスやパラメータ）と一致し、かつHTTPメソッドが正しい場合に該当のメソッドが呼び出されます。
その他のアノテーションについても、ここで触れておきます。

**@&#xFFF0;Autowired**
クラスのフィールドに付与することでインスタンスを自動的に注入してくれます。
（明示的にnewしてインスタンス化する必要が無くなる）
**@&#xFFF0;PathVariable**
URLに含まれる動的なパラメータを受け取るためのアノテーションです。
例えば、`http://localhost:8080/tasks/001`にGETリクエストがあった場合、getTaskメソッドはid=001を引数として受け取り、処理を行います。
**@&#xFFF0;RequestBody**
HTTPリクエストのボディに含まれるデータを受け取るためのアノテーションです。
通常、POSTやPUTリクエストなどのデータを追加、更新する処理で利用されます。

```java:TaskController.java
package com.example.restapidemo2.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.example.restapidemo2.model.Task;
import com.example.restapidemo2.service.TaskService;

@RestController
public class TaskController {

	@Autowired
	private TaskService taskService;

	@GetMapping("/tasks")
	public List<Task> getAllTasks() {
		return taskService.getAllTasks();
	}

	@GetMapping("/tasks/{id}")
	public Task getTask(@PathVariable("id") String id) {
		return taskService.getTask(id);
	}

	@PostMapping("/tasks")
	public void addTask(@RequestBody Task task) {
		taskService.addTask(task);
	}

	@PutMapping("/tasks/{id}")
	public void updateTask(@RequestBody Task task, @PathVariable("id") String id) {
		taskService.updateTask(id, task);
	}

	@DeleteMapping("/tasks/{id}")
	public void deleteTask(@PathVariable("id") String id) {
		taskService.deleteTask(id);
	}
}
```

## 動作確認
処理の実装ができましたので、アプリケーションを起動し、事前にインストールしておいたREST Clientで確認してみましょう。

### GET（全件取得）
REST Clientを起動したら、画面上部のリストからGETを選択し、URLの欄に以下を入力してください。
`http://localhost:8080/tasks`
送信ボタンを押下すると、画面下部のResponseタブにgetAllTasksメソッドで取得した全件のデータがJSON形式で表示されます。

```
[
  {
    "id": "001",
    "title": "掃除",
    "status": "TODO"
  },
  {
    "id": "002",
    "title": "洗濯",
    "status": "DONE"
  },
  {
    "id": "003",
    "title": "勉強",
    "status": "IN_PROGRESS"
  },
  {
    "id": "004",
    "title": "料理",
    "status": "TODO"
  },
  {
    "id": "005",
    "title": "買い物",
    "status": "DONE"
  }
]
```

### GET（1件取得）
idを指定した1件の取得についても同様にURLの末尾にidを指定することで、getTaskメソッドが呼び出されて取得することができます。
`http://localhost:8080/tasks/001`

```
{
  "id": "001",
  "title": "掃除",
  "status": "TODO"
}
```

### POST
データを送信し、タスクの一覧に追加します。
まず、画面上部のリストからPOSTを選択し、URLの欄に以下を入力してください。
`http://localhost:8080/tasks`
次に、URL欄下のタブからBODYを選択し、左右に表示されたリストから、「Raw Input」及び「JSON」を選択します。
画面中央の入力欄にJSON形式で以下のように入力し、送信ボタンを押下してください。

```
{
  "id": "006",
  "title": "運動",
  "status": "TODO"
}
```

画面下部にステータスコード：200が出ればOKです。
では、追加したデータをGETメソッドで確認してみましょう。
全件または1件のどちらでも良いですが、ここでは全件取得で確認してみたいと思います。
メソッドをGETに変更し、URLは以下の内容で送信ボタンを押下してください。
`http://localhost:8080/tasks`
※GETに変更した際、画面中央にHEADERSの行が1件追加されているので、右端の－ボタンで消しておいてください。

```
[
  {
    "id": "001",
    "title": "掃除",
    "status": "TODO"
  },
  {
    "id": "002",
    "title": "洗濯",
    "status": "DONE"
  },
  {
    "id": "003",
    "title": "勉強",
    "status": "IN_PROGRESS"
  },
  {
    "id": "004",
    "title": "料理",
    "status": "TODO"
  },
  {
    "id": "005",
    "title": "買い物",
    "status": "DONE"
  },
  {
    "id": "006",
    "title": "運動",
    "status": "TODO"
  }
]
```

6番目にPOSTメソッドで送信したデータが追加されていることが分かります。

### PUT
既存データに対して、id指定で内容を更新します。
画面上部のリストからPUTを選択し、今回はid：003のステータスをDONEに更新したいと思いますので、URLの欄に以下を入力してください。
`http://localhost:8080/tasks/003`
先程と同様に、URL欄下のタブからBODYを選択し、左右に表示されたリストから、「Raw Input」及び「JSON」を選択します。
画面中央の入力欄にJSON形式で以下のように入力し、送信ボタンを押下してください。

```
{
  "id": "003",
  "title": "勉強",
  "status": "DONE"
}
```

画面下部にステータスコード：200が出ればOKです。
では、追加したデータをGETメソッドで確認してみましょう。
今回はid指定の1件取得で確認してみたいと思います。
メソッドをGETに変更し、URLは以下の内容で送信ボタンを押下してください。
`http://localhost:8080/tasks/003`

```
{
  "id": "003",
  "title": "勉強",
  "status": "DONE"
}
```

無事、statusがDONEに更新されました。

### DELETE
既存データに対して、id指定でデータを削除します。
画面上部のリストからDELETEを選択し、先程追加したid：006を削除したいと思いますので、URLの欄に以下を入力して、送信ボタンを押下してください。
`http://localhost:8080/tasks/006`
画面下部にステータスコード：200が出ればOKです。

今度は全件取得でデータを確認してみましょう。
メソッドをGETに変更し、URLは以下の内容で送信ボタンを押下してください。
`http://localhost:8080/tasks`

```
[
  {
    "id": "001",
    "title": "掃除",
    "status": "TODO"
  },
  {
    "id": "002",
    "title": "洗濯",
    "status": "DONE"
  },
  {
    "id": "003",
    "title": "勉強",
    "status": "DONE"
  },
  {
    "id": "004",
    "title": "料理",
    "status": "TODO"
  },
  {
    "id": "005",
    "title": "買い物",
    "status": "DONE"
  }
]
```

id：006が削除されていることが確認できます。

## おわりに
最後までご覧いただきありがとうございます。
今回はなるべく簡単にSpring Bootを活用してREST APIを実装する内容になっておりますので、DB接続やエラーハンドリングは省きましたが、また別の機会にその辺りも記事に出来ればと思います。