Web アプリ開発を学び始めたとき、多くの人が最初につまずくのが REST API です。
「GET と POST の違いは?」「どんな構造で作ればいいの?」と、概念がいきなり抽象的でピンと来ない人も多いはず。
そこで本記事では、Spring Boot を使って 日本語 × 英語の対訳名言(ことわざ)を返す REST API を、実際に手を動かしながら作っていきます。
たとえば——
「郷に入っては郷に従え」
“When in Rome, do as the Romans do.”
こんな日英ペアの名言を返す API を題材にすることで、データ構造がシンプルになり、初学者でも REST の流れを直感的に理解できます。
セキュリティや高度な設定はひとまず置いておき、Spring の基礎と REST API の作り方を “楽しみながら” 身につけること がこのハンズオンの目的です。
それでは、さっそく Spring Boot を使って、名言 API を作る旅に出かけましょう!
作成
- 新規SpringStarterProject

- 設定例

- 依存関係(SpringBootのバージョンは3.5.X)を選択すること!
- 4系は不可(設定が変わってきます)

H2DataBase設定
- src/main/resources/application.propartiesに追記する
- DB接続URL、ユーザー名、パスワードを設定(今回パスワードは不要とした)
- SafariでJSONが文字化けすることがあるので文字コード送信を必須とする
spring.application.name=RomansDo
# DB接続設定
spring.datasource.url=jdbc:h2:mem:romansdo
spring.datasource.username=sa
spring.datasource.password=
# 強制 UTF-8(Safari の文字化け防止)
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true以下の2枚のファイルを作成し配置する
- src/main/resources/schema.sql
CREATE TABLE quotes(
id INT AUTO_INCREMENT PRIMARY KEY,
jp VARCHAR(255) NOT NULL,
en VARCHAR(255) NOT NULL,
description VARCHAR(500)
);- src/main/resources/data.sql
INSERT INTO quotes (jp, en, description) VALUES
('郷に入っては郷に従え', 'When in Rome, do as the Romans do', 'その土地の習慣に従うと物事がうまくいくという意味'),
('七転び八起き', 'Fall down seven times, stand up eight', '何度失敗してもあきらめず立ち上がること'),
('塵も積もれば山となる', 'Little by little, a little becomes a lot', '小さな努力の積み重ねが大きな成果につながる'),
('猿も木から落ちる', 'Even monkeys fall from trees', 'どんな名人でも失敗することがあるという教え'),
('急がば回れ', 'More haste, less speed', '急ぐときほど遠回りでも安全な道を選んだ方がよいという意味');
起動確認
無事にアプリが起動するか確かめよう。
- RomansDoApplication.javaを右クリックからSpringBootアプリケーションを実行する

- エラーが起こらずにサーバーとDBが起動すれば成功だ。

DBの確認
- ブラウザから以下のURLでアクセスすることでDB管理ページにアクセスできる
http://localhost:8080/h2-console/- application.propartyで設定した情報を入力してconnect

- 以下のように表示されれば成功だ。
- テーブル名やカラム名が大文字に変換されているがこれはH2DBのデフォルトの挙動だ。

Entity
DBの構成に紐づくEntityを以下のように作成する

- com.example.romansdo.entity.Quote.java
package com.example.romansdo.entity;
import org.springframework.data.annotation.Id;
@Table("QUOTES")
public class Quote {
@Id
private Integer id;
private String jp;
private String en;
private String description;
public Quote() {
}
public Quote(Integer id, String jp, String en, String description) {
this.id = id;
this.jp = jp;
this.en = en;
this.description = description;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getJp() {
return jp;
}
public void setJp(String jp) {
this.jp = jp;
}
public String getEn() {
return en;
}
public void setEn(String en) {
this.en = en;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
ポイント
- @Table(“QUOTES”)
- 実際のテーブル名を指定
- @id
- @Id が無いと、Spring Data JDBC は どのフィールドが PK(主キー)か判断できない。
- @Id を付けると以下が可能となる
- SELECT 時:主キーとしてマッピング
- NSERT 時:PK の扱いが自動
- UPDATE 時:PK 指定で更新
- DELETE 時:PK 指定で削除
- 引数のないコンストラクタ
- Spring Data JDBC では引数なしコンストラクタは必須ではないが、フレームワークやJSON
デシリアライズとの相性が良いため実装しておくのがおすすめ。
- Spring Data JDBC では引数なしコンストラクタは必須ではないが、フレームワークやJSON
Repository
- 以下の階層にQuoteRepositoryインターフェイスを作成する

- com.example.romansdo.repository.QuoteRepository.java
package com.example.romansdo.repository;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import com.example.romansdo.entity.Quote;
public interface QuoteRepository extends CrudRepository<Quote,Integer>{
List<Quote> findAll();
}
ポイント
- CrudRepository<Quote, Integer>
- 第2引数は主キーの型(今回はint)
- List<Quote> findAll()
- 親インターフェイスで定義されているのはIterable<T>,このままだと取得後に一手間必要になるので、シャドーイングで戻り値を再定義している。こうしておくと取得したものがList<Quote>になる
- 実装クラスは Spring Data JDBC が自動生成(書く必要なし)
Controller
- それではリクエストに応じたJSONを返却するRestControllerを作成しよう

- com.example.romansdo.controller.QuoteController.java
Get 全件取得
package com.example.romansdo.controller;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.romansdo.repository.QuoteRepository;
@RestController
@RequestMapping("/quotes")
public class QuoteController {
private final QuoteRepository repository;
public QuoteController(QuoteRepository repository) {
this.repository=repository;
}
// -----------------------
// 全件取得 GET /quotes
// -----------------------
@GetMapping
public Map<String, Object> getAll() {
return Map.of(
"success", true,
"data", repository.findAll()
);
}
}ポイント
- @RestController
- 戻り値を自動的にJSONに変換してレスポンスする
検証
では実際にDBのデータがJSONで取得できるかやってみよう。Get通信はブラウザでできるので以下のURLでアクセスしてみよう。
http://localhost:8080/quotes- 以下のようにJSONデータが取得できれば成功だ
- 以下の表示はブラウザにJSON表示の拡張機能が入っている場合の表示、拡張機能が入っていない場合はプレーンなJSON文字列になる

Get 1件
- idを指定して1件取得するControllerを以下のように追記する
package com.example.romansdo.controller;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.romansdo.repository.QuoteRepository;
@RestController
@RequestMapping("/quotes")
public class QuoteController {
private final QuoteRepository repository;
public QuoteController(QuoteRepository repository) {
this.repository=repository;
}
// -----------------------
// 全件取得 GET /quotes
// -----------------------
@GetMapping
public Map<String, Object> getAll() {
return Map.of(
"success", true,
"data", repository.findAll()
);
}
// -----------------------
// 1件取得 GET /quotes/{id}
// -----------------------
@GetMapping("/{id}")
public Map<String, Object> getById(@PathVariable Integer id) {
return repository.findById(id)
.map(q -> Map.of(
"success", true,
"data", q
))
.orElse(Map.of(
"success", false,
"error", "Quote not found"
));
}
}ポイント
- @GetMapping(“/{id}”) ~ @PathVariable Integer id
- {id} と書いておくと、URL に含まれた数字(例:/quotes/3 の「3」)がそのまま取り出され、@PathVariable Integer id としてメソッドの引数に格納される。つまり、URL に入ってきた ID を そのままメソッド内で使えるようになる仕組み 。
- return 以降(34行目~)
- 指定されたidのデータの有無で作成するMapを変えている
- その返されたMapを@RestControllerによってJSONに変換されレスポンスされる
検証
- ブラウザからidを指定してアクセスしてみよう
http://localhost:8080/quotes/3
- 指定されたidデータがない場合もためそう
http://localhost:8080/quotes/10
このような作りにしておくとクライアントフレンドリーなAPIとすることができる。
(厳密なRESTでは404を返すように設計することが推奨されている)
Post
- データをPostしてみよう。この場合登録したいデータをJSONで用意して(idは無し)Post通信をする
- Controllerに以下の部分を追記
package com.example.romansdo.controller;
import java.util.Map;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.romansdo.entity.Quote;
import com.example.romansdo.repository.QuoteRepository;
@RestController
@RequestMapping("/quotes")
public class QuoteController {
private final QuoteRepository repository;
public QuoteController(QuoteRepository repository) {
this.repository=repository;
}
// -----------------------
// 全件取得 GET /quotes
// -----------------------
@GetMapping
public Map<String, Object> getAll() {
return Map.of(
"success", true,
"data", repository.findAll()
);
}
// -----------------------
// 1件取得 GET /quotes/{id}
// -----------------------
@GetMapping("/{id}")
public Map<String, Object> getById(@PathVariable Integer id) {
return repository.findById(id)
.map(q -> Map.of(
"success", true,
"data", q
))
.orElse(Map.of(
"success", false,
"error", "Quote not found"
));
}
// -----------------------
// 新規作成 POST /quotes
// -----------------------
@PostMapping
public Map<String, Object> create(@RequestBody Quote quote) {
Quote saved = repository.save(quote);
return Map.of(
"success", true,
"data", saved
);
}
}検証
- ターミナルから以下のコマンドを入力
curl -X POST http://localhost:8080/quotes \
-H "Content-Type: application/json" \
-d '{
"jp": "笑う門には福来る",
"en": "Fortune comes to a merry home",
"description": "笑顔でいれば良いことが起きるという意味"
}' \
-w "\n"- curl(カール)は、コマンドラインから HTTP リクエストを送れるツールで、今回のようなAPI の動作確認にとても便利だ。
- オプションの意味は下記
| オプション | 正しい意味 | よく使う用途 |
|---|---|---|
-X | HTTP Method | GET / POST / PUT / DELETE 指定 |
-H | Header | Content-Type、Token など |
-d | Data | JSON や form 値の送信 |
| -w | write-out | 改行などを出力(任意) |
- 以下のように表示されれば成功だ

Put
- Controllerに以下を追加
// -----------------------
// 更新 PUT /quotes/{id}
// -----------------------
@PutMapping("/{id}")
public Map<String, Object> update(
@PathVariable Integer id,
@RequestBody Quote newQuote) {
return repository.findById(id)
.map(q -> {
q.setJp(newQuote.getJp());
q.setEn(newQuote.getEn());
q.setDescription(newQuote.getDescription());
Quote updated = repository.save(q);
return Map.of(
"success", true,
"data", updated
);
})
.orElse(Map.of(
"success", false,
"error", "Quote not found"
));
}- curl
curl -X PUT http://localhost:8080/quotes/3 \
-H "Content-Type: application/json" \
-d '{
"jp": "塵も積もれば山となる(改訂版)",
"en": "Little by little, a little becomes a lot (updated)",
"description": "少しずつの積み重ねが大きな成果につながるという意味(更新)"
}' \
-w "\n"
検証
- 以下のようになれば成功だ

Delete
- 最後にDeleteだ。
// -----------------------
// 削除 DELETE /quotes/{id}
// -----------------------
@DeleteMapping("/{id}")
public Map<String, Object> delete(@PathVariable Integer id) {
boolean exists = repository.existsById(id);
if (!exists) {
return Map.of(
"success", false,
"error", "Quote not found"
);
}
repository.deleteById(id);
return Map.of(
"success", true
);
}curl -X DELETE http://localhost:8080/quotes/4 \
-w "\n"検証

完成!
今回のハンズオンでは、Spring Boot と Spring Data JDBC を使って、
日本語 × 英語の名言を返すシンプルな REST API を作成しました。
- H2 データベースの初期化
- Entity/Repository/Controller の実装
- JSON の入出力
- curl を使った API のテスト
- POST/PUT/DELETE といった CRUD 操作
と、一通りの流れを体験できたことで、
Spring で REST API を構築する基本の考え方が掴めたのではないでしょうか。
Spring は最初こそ“設定が多いフレームワーク”と感じますが、
実際に手を動かしてみると、
REST API を作るための仕組みがすでに揃っていることがよく分かります。
次回からは今回完成した API を、
様々なクライアントアプリから呼び出してみたいと思います。
それでは、次のステップも楽しみながら進めていきましょう!
お疲れさまでした!

コメント