Java + Spring Boot + PostgreSQL + Spring Data REST でREST API
ついにタイトルに docker-compose が入らなくなりました笑
TL;DR
- 前回の記事の続きというか+αでやっています
- docker-compose 下で Java + Spring Boot + PostgreSQL (JPA編) | 北山淳也 | zenn
- このへんの記事と大体同じです
- Spring JPA Data with REST と Lombokで恐ろしく簡単にREST APIを作成する。 | Qiita
- Spring Boot with Docker な開発環境を考える | tiqwablog
Spring Data REST を使う準備
Spring Data REST というのは下記記事でも少し触れたのですが、
Entity と Repository を用意するだけで
RESTful な Endpoint が全部生える便利なパッケージです。
- docker-compose 下で Java + Spring Boot + 簡単なWeb API を作ってみる | 北山淳也 | zenn
ので準備といっても前回の記事の状態から server/build.gradle に
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
を追記するだけです。
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
...
Spring Initializr だとこんな感じですね。
- Spring Initializr
前回の記事の状態からコードの変更も不要です。すごい(小学生並みの感想)
Docker コンテナを起動してGradleビルド, アプリケーション起動, リクエストを投げてみる
docker-compose up -d
# DB が立ち上がって初期化されるまでちょっとかかるのでちょっと待つ
docker-compose exec app bash
bash-4.4# sh gradlew build
...
BUILD SUCCESSFUL in 8m 41s
5 actionable tasks: 5 executed
# できてるのを確認
bash-4.4# ls build/libs/
app-0.0.1-SNAPSHOT.jar
bash-4.4# java -jar build/libs/app-0.0.1-SNAPSHOT.jar
起動したらリクエストを投げてみましょう。
$ curl http://localhost:8080/users -X GET
{
"_embedded" : {
"users" : [ {
"name" : "test",
"_links" : {
"self" : {
"href" : "http://localhost:8080/users/1"
},
"user" : {
"href" : "http://localhost:8080/users/1"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/users"
},
"profile" : {
"href" : "http://localhost:8080/profile/users"
}
}
}
取れてる! すごい!
POST リクエストでデータの登録もできます。
$ curl http://localhost:8080/users -X POST -H "Content-Type:application/json" -d '{ "name":"foo" }'
{
"name" : "foo",
"_links" : {
"self" : {
"href" : "http://localhost:8080/users/2"
},
"user" : {
"href" : "http://localhost:8080/users/2"
}
}
}
$ curl http://localhost:8080/users -X POST -H "Content-Type:application/json" -d '{ "name":"bar" }'
{
"name" : "bar",
"_links" : {
"self" : {
"href" : "http://localhost:8080/users/3"
},
"user" : {
"href" : "http://localhost:8080/users/3"
}
}
再度 GET リクエストしてみましょう。
curl http://localhost:8080/users -X GET
{
"_embedded" : {
"users" : [ {
"name" : "test",
"_links" : {
"self" : {
"href" : "http://localhost:8080/users/1"
},
"user" : {
"href" : "http://localhost:8080/users/1"
}
}
}, {
"name" : "foo",
"_links" : {
"self" : {
"href" : "http://localhost:8080/users/2"
},
"user" : {
"href" : "http://localhost:8080/users/2"
}
}
}, {
"name" : "bar",
"_links" : {
"self" : {
"href" : "http://localhost:8080/users/3"
},
"user" : {
"href" : "http://localhost:8080/users/3"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/users"
},
"profile" : {
"href" : "http://localhost:8080/profile/users"
}
}
}
id をURIで指定することでその id のデータだけをGETすることももちろん可能です。
$ curl http://localhost:8080/users/3 -X GET
{
"name" : "bar",
"_links" : {
"self" : {
"href" : "http://localhost:8080/users/3"
},
"user" : {
"href" : "http://localhost:8080/users/3"
}
}
}
PUT リクエストで更新もできます。
$ curl http://localhost:8080/users/3 -X PUT -H "Content-Type:application/json" -d '{ "name":"piyo" }'
{
"name" : "piyo",
"_links" : {
"self" : {
"href" : "http://localhost:8080/users/3"
},
"user" : {
"href" : "http://localhost:8080/users/3"
}
}
}
$ curl http://localhost:8080/users/3 -X GET
{
"name" : "piyo",
"_links" : {
"self" : {
"href" : "http://localhost:8080/users/3"
},
"user" : {
"href" : "http://localhost:8080/users/3"
}
}
}
ワーオ。ワーオですねこれは。
http://localhost:9000
で Adminer にログインして
データベースにも登録されてるのか見てみましょう。
登録されてますね! OKです!
超簡単な RESTfull API を用意するのなら Rails より早いのではないでしょうか……?笑
トラブルシュート:POSTで登録できない時
POST リクエストを投げた時にコードの状態によっては 500 ERROR になることがあります。
どういうエラーなのかは java -jar build/libs/app-0.0.1-SNAPSHOT.jar
を実行して
Spring Boot アプリケーションが立ち上がってる方にログが出てるはずです。
ERROR:relation "hibernate_sequence" does not exist
PostgreSQL の SERIAL 列に対してEntityクラスの @GeneratedValue
の対応付けが間違っている可能性があります。
今回のコードであれば以下の部分を確認してみてください。
package com.example.app.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "users")
public class User {
@Id
// ここが @GeneratedValue(strategy = GenerationType.IDENTITY) かを確認
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
protected User() {}
public User(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return String.format("{id:%d,name:%s}", id, name);
}
}
- PostgreSQL+JPAのIDカラムで「relation "hibernate_sequence" does not exist」となったときの対処 | Qiita
- @GeneratedValueを使って主キーを生成する方法 | Qiita
ERROR:permission denied for sequence user_id_seq
今回は appuser というユーザを作成して appサーバーから PostgreSQL に接続していますが、
appuser に SEQUENCES に対して SELECT 権限がないと SERIAL 列に id のインクリメント発行時にエラーになります。
今回のコードであれば以下の部分を確認してみてください。
CREATE ROLE appuser WITH LOGIN PASSWORD 'apppass';
GRANT SELECT,UPDATE,INSERT,DELETE ON ALL TABLES IN SCHEMA public TO appuser;
-- この下の行がちゃんとあるか確認
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO appuser;
- sql - ERROR: permission denied for sequence cities_id_seq using Postgres | Stack Overflow
なお、forDocker/db/initdb
配下のクエリを編集した場合は
今回の docker-compose.yml であれば docker volume を割り当てているので
dbvol を docker volume rm ...
で削除してやれば再度実行させることができます。
今回のリポジトリはこちらです。
参考
- Spring JPA Data with REST と Lombokで恐ろしく簡単にREST APIを作成する。 | Qiita
- Spring Data RESTでのHTTPエンドポイントのカスタマイズ
- Spring Boot with Docker な開発環境を考える | tiqwablog
- Tutorial | React.js and Spring Data REST | Spring
- Spring BootでSpring Data RESTを試す | abcdefg.....
Discussion
「今回のコードであれば以下の部分を確認してみてください。」とか
偉そうに書いてるけど今回の記事を書き始めてから前回の記事を修正したのは内緒です(これが原因でハマッた人がいたらごめんなさい、のでトラブルシュートとして書きました🙇♂️)
タイトル制限とりあえず近いうちに+10字します…😹
@catnose さん
ありがとうございます!私ももうちょっとシンプルにタイトルつけるようにします 🙇♂️