Kotlin + SpringWeb + Spring Data JDBC で Web API サーバーを作成する
概要
本記事では、Java の O/R マッパの 1 つである Spring Data JDBC を用いて、簡単な Web API サーバを作成する例を紹介します。
以下の構成で紹介していきます。
- 「Spring Data JDBC について」
- 「Kotlin(Sprint Boot)+ Spring Data JDBC で Web API サーバを作成」
- 「まとめ」
本記事で作成したサンプルコードは以下です。
Spring Data JDBC について
Sprint Data JDBC は、Spring Data の 1 種類です。
Spring Data は、さまざまな手法目的(RDS、NoSQL、Reactive、Redis)に対して、Spring のように記述可能なインタフェースの提供を目的にしています。
Spring Data JDBC は JDBC をベースにしたデータアクセスを目的としています。
JDBC の単純さ(遅延読み込みやキャシュをしないなど)を残しつつ、簡潔なメソッド(12 種類のみ)の提供と、それ以上の操作は@Query
アノテーションによる自作によって対応します。
他にも、ドメイン駆動設計(DDD)の「リポジトリ」「集約」「集約ルート」の概念に影響を受けた実装になっています。
詳細な説明を省きますので、気になる方は以下のリファレンスを参考にしてみてください。
Kotlin(Sprint Boot)+ Spring Data JDBC で Web API サーバを作成
Spring Initializr
Spring Initializr を用いて、ひな型を作成します。
以下のリンクから、Spring Initializr の画面を開いてください。
設定の項目は以下になります。
「GENERATE」を押下して、zip ファイルをダウンロードしたら、自身のディレクトリに配置して解凍してください。
項目 | 要素 |
---|---|
Project | Gradle Project |
Language | Kotlin |
Spring Boot | 2.7.5 |
Project Metadata Artifact | kotlin-spring-data-jdbc-web-api-demo |
Project Metadata Name | kotlin-spring-data-jdbc-web-api-demo |
Packaging | Jar |
Java | 17 |
Dependencies | Spring Web、Spring Data JDBC、PostgreSQL Driver |
Spring Initializr
DB
DB は docker compose を利用します。
docker-compose.yml は以下を利用してください。
今回使用する docker-compose.yml。
---
version: '3.8'
services:
#
# PostgreSQL
#
sample-pg:
image: postgres:14-bullseye
container_name: sample-pg
ports:
- 5432:5432
environment:
POSTGRES_USER: sample-user
POSTGRES_PASSWORD: sample-pass
POSTGRES_DB: sample-db
POSTGRES_INIT_DB_ARGS: --encoding=UTF-8
volumes:
- type: bind
source: ${PWD}/sql/
target: /docker-entrypoint-initdb.d/
初期値を挿入するために、SQL を配置してください。
初期値挿入のための SQL。
DROP TABLE IF EXISTS customer;
CREATE TABLE IF NOT EXISTS customer (
id SERIAL
, first_name VARCHAR(255)
, last_name VARCHAR(255)
);
INSERT INTO customer ( first_name, last_name ) VALUES
( 'Alice', 'Sample1' )
, ( 'Bob', 'Sample2' )
;
application.propeties
DB との接続のためには、application.properties の設定が必要です。該当ファイルに対して、以下の内容を記述してください。
#
# DB
#
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/sample-db
spring.datasource.username=sample-user
spring.datasource.password=sample-pass
spring.datasource.driver-class-name=org.postgresql.Driver
実装
これから、Spring Data JDBC の基本的な実装を説明します。
以下の流れで実装します。
- DB のテーブルに該当するエンティティを定義
-
CrudRepository<T, ID>
を実装した リポジトリ interface を作成 - コントローラやサービスで、リポジトリを使用
エンティティ
テーブルに該当するエンティティを定義します。
以下の実装では、customer テーブルに相当するデータクラスCustomer
を実装しました。
テーブル名を@Table
で指定し、オートインクリメントをしているカラムには@Id
を指定します。
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
@Table("customer")
data class Customer(
@Id val id: Int,
val firstName: String,
val lastName: String,
)
他のアノテーションについては以下を参照してください。
リポジトリ
Spring JDBC では、CrudRepository
を実装することで、エンティティに CRD 処理の実行可能なリポジトリを作成可能です。
メソッド自体の準備はこれで完了です。
CrudRepository
に定義されている 12 種類のメソッドをエンティティに対して実行可能です。
12 種類の中に Update の処理は含まれておらず、自作するには @Query
を利用する必要があります。
import com.example.kotlinspringdatajdbcwebapidemo.entity.Customer
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
@Repository
interface CustomerRepository : CrudRepository<Customer, Int>
コントローラ
コントローラを用意して、DB 操作します。
それぞれ以下の API メソッドを用意しています。
メソッド | パス | 用途 |
---|---|---|
GET | /customers/{id} | 単一取得 |
GET | /customers | 全件取得 |
POST | /customers | 追加 |
DELETE | /customers/{id} | 削除 |
import com.example.kotlinspringdatajdbcwebapidemo.entity.Customer
import com.example.kotlinspringdatajdbcwebapidemo.repository.CustomerRepository
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.RequestBody
import org.springframework.web.bind.annotation.RestController
@RestController
class CustomerController(private val customerRepository: CustomerRepository) {
@GetMapping("/customers/{id}")
fun getById(@PathVariable id: Int) = customerRepository.findById(id)
@GetMapping("customers")
fun getList(): MutableIterable<Customer> = customerRepository.findAll()
@PostMapping("/customers")
fun insert(@RequestBody customer: Customer) = customerRepository.save(customer)
@DeleteMapping("/customers/{id}")
fun delete(@PathVariable id: Int) = customerRepository.deleteById(id)
}
動作確認
実装自体は完了ですが、念の為動作確認します。
DB の起動
以下のコマンドで起動してください。
docker compose up
db をやめて、コンテナを削除するとき。
# Ctrl + c で止めてから
docker compose down
サーバの起動
Sprint Boot は以下のコマンドで起動できます。
http://localhost:8080
でサーバが起動されます。
./gradlew bootRun
動作確認
それぞれのリクエストでの動作確認の方法をまとめました。
それぞれ折り畳んだので、確認してみてください。
単一取得。
curl --location --request GET 'http://localhost:8080/customers/1' | jq .
{
"id": 1,
"firstName": "Alice",
"lastName": "Sample1"
}
全件取得。
curl --location --request GET 'http://localhost:8080/customers' | jq .
[
{
"id": 1,
"firstName": "Alice",
"lastName": "Sample1"
},
{
"id": 2,
"firstName": "Bob",
"lastName": "Sample2"
}
]
追加。
curl --location --request POST 'http://localhost:8080/customers' \
--header 'Content-Type: application/json' \
--data-raw '{
"firstName": "Carol",
"lastName": "Sample3"
}' | jq .
{
"id": 3,
"firstName": "Carol",
"lastName": "Sample3"
}
curl --location --request GET 'http://localhost:8080/customers' | jq .
[
{
"id": 1,
"firstName": "Alice",
"lastName": "Sample1"
},
{
"id": 2,
"firstName": "Bob",
"lastName": "Sample2"
},
{
"id": 3,
"firstName": "Carol",
"lastName": "Sample3"
}
]
削除。
curl --location --request DELETE 'http://localhost:8080/customers/3' | jq .
レスポンスなし
curl --location --request GET 'http://localhost:8080/customers' | jq .
[
{
"id": 1,
"firstName": "Alice",
"lastName": "Sample1"
},
{
"id": 2,
"firstName": "Bob",
"lastName": "Sample2"
}
]
まとめ
Spring Data を利用した、Web API の作成方法を紹介しました。
DB のテーブル定義から簡単に CRD の処理を記述可能なことがわかりました。
個人的な感想としては、Repository に Spring Data の interface を継承させる実装について気になりました。DDD では、ドメイン層に技術を依存させるのを避けるため、どのように扱うのか気になりました。
本記事の紹介した範囲では、テーブルとモデルが密結合していたり、JOIN や UPDATE ができなかったりするので、ぜひアレンジしてみてください。
参考
Spring Data を用いた主な実装方法は以下を参考にしました。
他は、公式リファレンスです。
Discussion