2
3

SpringBootでREST APIを実装してみた

Last updated at Posted at 2023-09-29

今回は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は各自書き換えておいてください。

src/min/resource/application.yml
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クラスを作成します。

src/main/java/com/example/sampleapi/entity/User.java
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を実装していきます。

src/main/java/com/example/sampleapi/repository/UserRepository.java
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クラスは実際にリクエストを受け付ける部分になります。

src/main/java/com/example/sampleapi/controller/UserController.java
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を体験するための実装になっているので、エラーハンドリングとかビジネスロジックとか全然書いていないので、そこはご了承ください...。

また、今回実装した内容はこちらにあります。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3