今回はSpringBootでREST APIを実装してみます。
動作環境
MySQL:8.0
SpringBoot:3.1.4
Java:17
APIのインターフェース
今回実装するAPIのインターフェースは下記になります。
endpoint | method | note |
---|---|---|
{host}/api/users | POST | ユーザーの作成 |
{host}/api/users/ | GET | ユーザー全件取得 |
{host}/api/users/:id | GET | 指定したIDのユーザーを取得 |
{host}/api/users/:id | PUT | 指定したIDのユーザー情報を変更 |
{host}/api/users/:id | DELETE | 指定したIDのユーザーを削除 |
データベースの準備
今回はMySQLを使います。
データベースとテーブルを下記のように作成しておいてください。
CREATE DATABASE sample_api;
USE sample_api;
CREATE TABLE users (
id BIGINT(20) AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(1024) NOT NULL,
email VARCHAR(1024) NOT NULL
);
APIの実装
Spring Initializrでプロジェクト作成
まずはSpring Initializrでプロジェクトを作成します。(Intellijとかお持ちの方は同じような内容でNew ProjectしていただいてもOKです)
リンクを開いていただいたら、今回扱う設定内容が反映されているので、そのままGENERATEを押してプロジェクトをダウンロードしてください。
任意のIDE等で開いていただいたら、下記のファイルだけ名称を変更します。(やらなくてもいいですが自分はyml形式が好きなので。。。)
src/main/resource/application.properties -> src/main/resource/application.yml
データベースの接続情報設定
次にデータベースの接続情報を設定ファイルに追記します。
username, passwordは各自書き換えておいてください。
spring:
datasource:
url: jdbc:mysql://localhost:3306/sample_api
username: {user_name}
password: {password}
driverClassName: com.mysql.cj.jdbc.Driver
SpringApplicationの起動
ここまでできたら一旦SpringApplicationを起動して、初期設定に問題がないか確認しておきましょう。
起動したら下記のようになっていれば大丈夫です。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.1.4)
2023-09-29T16:35:00.542+09:00 INFO 77060 --- [ main] c.e.sampleapi.SampleApiApplication : Starting SampleApiApplication using Java 17.0.6 with PID 77060 (/Users/.../Downloads/sample-api/target/classes started by yunosukenaito in /Users/yunosukenaito/Downloads/sample-api)
2023-09-29T16:35:00.543+09:00 INFO 77060 --- [ main] c.e.sampleapi.SampleApiApplication : No active profile set, falling back to 1 default profile: "default"
2023-09-29T16:35:00.743+09:00 INFO 77060 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2023-09-29T16:35:00.749+09:00 INFO 77060 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 4 ms. Found 0 JPA repository interfaces.
2023-09-29T16:35:00.932+09:00 INFO 77060 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2023-09-29T16:35:00.936+09:00 INFO 77060 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-09-29T16:35:00.936+09:00 INFO 77060 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.13]
2023-09-29T16:35:00.970+09:00 INFO 77060 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-09-29T16:35:00.970+09:00 INFO 77060 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 408 ms
2023-09-29T16:35:01.015+09:00 INFO 77060 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2023-09-29T16:35:01.154+09:00 INFO 77060 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@1d7eb170
2023-09-29T16:35:01.155+09:00 INFO 77060 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2023-09-29T16:35:01.171+09:00 INFO 77060 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2023-09-29T16:35:01.198+09:00 INFO 77060 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.2.9.Final
2023-09-29T16:35:01.199+09:00 INFO 77060 --- [ main] org.hibernate.cfg.Environment : HHH000406: Using bytecode reflection optimizer
2023-09-29T16:35:01.255+09:00 INFO 77060 --- [ main] o.h.b.i.BytecodeProviderInitiator : HHH000021: Bytecode provider name : bytebuddy
2023-09-29T16:35:01.306+09:00 INFO 77060 --- [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
2023-09-29T16:35:01.376+09:00 INFO 77060 --- [ main] o.h.b.i.BytecodeProviderInitiator : HHH000021: Bytecode provider name : bytebuddy
2023-09-29T16:35:01.463+09:00 INFO 77060 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2023-09-29T16:35:01.465+09:00 INFO 77060 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2023-09-29T16:35:01.479+09:00 WARN 77060 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2023-09-29T16:35:01.615+09:00 INFO 77060 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-09-29T16:35:01.619+09:00 INFO 77060 --- [ main] c.e.sampleapi.SampleApiApplication : Started SampleApiApplication in 1.267 seconds (process running for 1.53)
Entityの実装
まずはEntityを実装します。entityのディレクトリを作成してその下にUserクラスを作成します。
package com.example.sampleapi.entity;
import jakarta.persistence.*;
import lombok.Data;
@Data
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "email")
private String email;
}
@Entityアノテーションを付与することで、このクラスがデータベースのEntityであることを示します。
@Tableアノテーションは、データベースのどのテーブルに対応するかを指定します。(先ほど作成したusersテーブルに対応)
@Idアノテーションでテーブルの主キーであることを明示し、@GenerateValueのIDENTITYを指定することで、データを追加時に自動的に主キーを生成することができます。
@Columnアノテーションは、テーブルのカラムとプロパティ名を紐づけます。
Repositoryの実装
次はRepositoryを実装していきます。
package com.example.sampleapi.repository;
import com.example.sampleapi.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
@Repositoryは、このインターフェースがリポジトリとして使用されることを示すために付与します。また、JpaRepositoryをextendsすることで、usersテーブルに対して、データの追加や更新・削除などのメソッドを使うことができます。
拡張をしたい場合は自身で定義したこのインターフェースのクラスにメソッドを追加していく形になります。
JpaRepositoryには対象のEntityクラスと主キーとなる型を指定します。
使えるメソッドは公式ドキュメント(JpaRepository)を参照してみてください。
Controllerの実装
最後にControllerクラスを実装します。Controllerクラスは実際にリクエストを受け付ける部分になります。
package com.example.sampleapi.controller;
import com.example.sampleapi.entity.User;
import com.example.sampleapi.repository.UserRepository;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
private UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping
public List<User> getAll() {
return this.userRepository.findAll();
}
@GetMapping("{id}")
public User getById(@PathVariable("id") Long id) {
return this.userRepository.findById(id).orElseThrow();
}
@PostMapping
public void save(@RequestBody User user) {
this.userRepository.save(user);
}
@PutMapping("{id}")
public void update(@PathVariable("id") Long id, @RequestBody User user) {
user.setId(id);
this.userRepository.save(user);
}
@DeleteMapping("{id}")
public void delete(@PathVariable("id") Long id) {
this.userRepository.deleteById(id);
}
}
@RestControllerでこのクラスがREST APIのコントローラークラスであることを示します。このアノテーションを付与することで、HTTPリクエストを受け取り、レスポンスを返すためのメソッドが提供されます。
@RequestMappingのアノテーションでエンドポイントの共通部分を設定します。
あとは@GetMappingや@PostMappingなどそれぞれHTTPリクエストに応じたエンドポイントを作成するためのアノテーションを付与しメソッドを作成していきます。
動作確認
ここまで実装できたら再度アプリケーションを実行して動作確認をしてみましょう。
ユーザー追加
2件ほどユーザーを追加してみます
curl -X POST -H "Content-Type: application/json" -d '{"name":"USER_001", "email":"user001@example.com"}' localhost:8080/api/users
curl -X POST -H "Content-Type: application/json" -d '{"name":"USER_002", "email":"user002@example.com"}' localhost:8080/api/users
データベースを確認してユーザーが追加されているか確認してみましょう。
mysql> select * from users;
+----+----------+---------------------+
| id | name | email |
+----+----------+---------------------+
| 1 | USER_001 | user001@example.com |
| 2 | USER_002 | user002@example.com |
+----+----------+---------------------+
2 rows in set (0.00 sec)
ユーザー取得
全件取得
% curl -X GET localhost:8080/api/users
[{"id":1,"name":"USER_001","email":"user001@example.com"},{"id":2,"name":"USER_002","email":"user002@example.com"}]
IDを指定して取得
% curl -X GET localhost:8080/api/users/1
{"id":1,"name":"USER_001","email":"user001@example.com"}
ユーザー更新
更新
% curl -X PUT -H "Content-Type: application/json" -d '{"name":"USER_001_UPDATE", "email":"user100_update@example.com"}' localhost:8080/api/users/1
更新されたか確認
% curl -X GET localhost:8080/api/users/1
{"id":1,"name":"USER_001_UPDATE","email":"user100_update@example.com"}
ユーザー削除
削除
% curl -X DELETE localhost:8080/api/users/2
削除されたか確認
% curl -X GET localhost:8080/api/users
[{"id":1,"name":"USER_001_UPDATE","email":"user100_update@example.com"}]
最後に
SpringBootでREST APIを実装してみました。
最短でREST APIを体験するための実装になっているので、エラーハンドリングとかビジネスロジックとか全然書いていないので、そこはご了承ください...。
また、今回実装した内容はこちらにあります。