The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

Spring Data RESTのエクステンション

RESTデータアクセスのエンドポイント生成には、REST Data with Panacheを使用することが推奨されますが、Quarkusでは、 spring-data-rest エクステンションとしてSpring Data RESTの互換性レイヤーを提供しています。

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 17+がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.9.9

  • 使用したい場合は、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

ソリューション

次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。

Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.gitアーカイブ をダウンロードします。

ソリューションは spring-data-rest-quickstart ディレクトリ にあります。

Mavenプロジェクトの作成

まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。

コマンドラインインタフェース
quarkus create app org.acme:spring-data-rest-quickstart \
    --extension='spring-data-rest,rest-jackson,quarkus-jdbc-postgresql' \
    --no-code
cd spring-data-rest-quickstart

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストールと使用方法の詳細については、 Quarkus CLI ガイドを参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.17.5:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=spring-data-rest-quickstart \
    -Dextensions='spring-data-rest,rest-jackson,quarkus-jdbc-postgresql' \
    -DnoCode
cd spring-data-rest-quickstart

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Windowsユーザーの場合:

  • cmdを使用する場合、(バックスラッシュ \ を使用せず、すべてを同じ行に書かないでください)。

  • Powershellを使用する場合は、 -D パラメータを二重引用符で囲んでください。例: "-DprojectArtifactId=spring-data-rest-quickstart"

このコマンドは、 spring-data-rest のエクステンションを持つ Maven プロジェクトを生成します。

すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリで以下のコマンドを実行することで、 spring-data-rest エクステンションをプロジェクトに追加することができます。

コマンドラインインタフェース
quarkus extension add spring-data-rest
Maven
./mvnw quarkus:add-extension -Dextensions='spring-data-rest'
Gradle
./gradlew addExtension --extensions='spring-data-rest'

これにより、ビルドファイルに以下が追加されます。

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-spring-data-rest</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-spring-data-rest")

さらに、以下の依存関係を追加する必要があります。

テストのためには、REST Assuredも必要です。これをビルドファイルに追加します。

pom.xml
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <scope>test</scope>
</dependency>
build.gradle
testImplementation("io.rest-assured:rest-assured")

注: resteasy-jacksonresteasy-jsonb の両方がサポートされており、交換することができます。

エンティティの定義

このガイドでは、以下のJPA Entityを使用しています。

package org.acme.spring.data.rest;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;

@Entity
public class Fruit {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    private String color;


    public Fruit() {
    }

    public Fruit(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

データベースアクセスプロパティの設定

application.properties に以下のプロパティを追加して、ローカルの PostgreSQL インスタンスへのアクセスを設定します。

quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=quarkus_test
quarkus.datasource.password=quarkus_test
quarkus.datasource.jdbc.url=jdbc:postgresql:quarkus_test
quarkus.datasource.jdbc.max-size=8
quarkus.hibernate-orm.database.generation=drop-and-create

この設定では、PostgreSQLがローカルで動作していることを前提としています。

それを実現する非常に簡単な方法は、以下のDockerコマンドを使用することです。

docker run -it --rm=true --name quarkus_test -e POSTGRES_USER=quarkus_test -e POSTGRES_PASSWORD=quarkus_test -e POSTGRES_DB=quarkus_test -p 5432:5432 postgres:14.1

別のセットアップを使用する予定の場合は、それに合わせて application.properties を変更してください。

データの準備

QuarkusにおけるSpring Data RESTの機能の一部を簡単に紹介するために、以下の内容を src/main/resources/import.sql という名前の新しいファイルに追加して、いくつかのテストデータをデータベースに挿入する必要があります:

INSERT INTO fruit(id, name, color) VALUES (1, 'Cherry', 'Red');
INSERT INTO fruit(id, name, color) VALUES (2, 'Apple', 'Red');
INSERT INTO fruit(id, name, color) VALUES (3, 'Banana', 'Yellow');
INSERT INTO fruit(id, name, color) VALUES (4, 'Avocado', 'Green');
INSERT INTO fruit(id, name, color) VALUES (5, 'Strawberry', 'Red');

Hibernate ORMは、アプリケーションの起動時にこれらのクエリを実行します。

リポジトリの定義

次に、 Fruit にアクセスするためのリポジトリを定義します。典型的なSpring Dataのやり方で、以下のようにリポジトリを作成します:

package org.acme.spring.data.rest;

import org.springframework.data.repository.CrudRepository;

public interface FruitsRepository extends CrudRepository<Fruit, Long> {
}

上記の FruitsRepository は、Spring Dataの org.springframework.data.repository.CrudRepository を拡張しており、後者のメソッドはすべて FruitsRepository で利用できることを意味しています。

spring-data-jpa エクステンションは、このリポジトリに対する実装を生成します。そして、 spring-data-rest エクステンションは、そのための REST CRUD リソースを生成します。

テストの更新

FruitsRepository の機能をテストするために、 FruitsRepositoryTest のコンテンツを次のように更新します。

package org.acme.spring.data.rest;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.core.IsNot.not;

@QuarkusTest
class FruitsRepositoryTest {

    @Test
    void testListAllFruits() {
        //List all, should have all 3 fruits the database has initially:
        given()
                .accept("application/json")
                .when().get("/fruits")
                .then()
                .statusCode(200)
                .body(
                        containsString("Cherry"),
                        containsString("Apple"),
                        containsString("Banana")
                );

        //Delete the Cherry:
        given()
                .when().delete("/fruits/1")
                .then()
                .statusCode(204);

        //List all, cherry should be missing now:
        given()
                .accept("application/json")
                .when().get("/fruits")
                .then()
                .statusCode(200)
                .body(
                        not(containsString("Cherry")),
                        containsString("Apple"),
                        containsString("Banana")
                );

        //Create a new Fruit
        given()
                .contentType("application/json")
                .accept("application/json")
                .body("{\"name\": \"Orange\", \"color\": \"Orange\"}")
                .when().post("/fruits")
                .then()
                .statusCode(201)
                .body(containsString("Orange"))
                .body("id", notNullValue())
                .extract().body().jsonPath().getString("id");

        //List all, Orange should be present now:
        given()
                .accept("application/json")
                .when().get("/fruits")
                .then()
                .statusCode(200)
                .body(
                        not(containsString("Cherry")),
                        containsString("Apple"),
                        containsString("Orange")
                );
    }
}

このテストは、 ./mvnw test を発行することで簡単に実行できます。

Maven
./mvnw test
Gradle
./gradlew test

アプリケーションをパッケージ化して実行する

Quarkus 開発モードは、他の Quarkus エクステンションと同じように、定義済みリポジトリーで機能し、開発サイクル中の生産性を大幅に向上させます。アプリケーションは、通常どおり、以下を使用して開発モードで起動できます。

コマンドラインインタフェース
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

アプリケーションをネイティブ・バイナリとして実行

もちろん、 ネイティブ実行可能ファイルの作成 ガイドの手順に従ってネイティブ実行可能ファイルを作成することもできます。

サポートされているSpring Data RESTの機能

Quarkusは現在、Spring Data RESTの機能のうち、最も便利でよく使われる機能のサブセットをサポートしています。

サポートされている内容

以下のセクションでは、Spring Data RESTの最も重要なサポートされている機能について説明します。

RESTエンドポイントの自動生成

以下のSpring Dataリポジトリを拡張するインターフェイスは、自動的にRESTエンドポイントが生成されます:

  • org.springframework.data.repository.CrudRepository

  • org.springframework.data.repository.PagingAndSortingRepository

  • org.springframework.data.jpa.repository.JpaRepository

上記のリポジトリから生成されたエンドポイントは、5つの一般的なREST操作を提供します。

  • GET /fruits - すべてのエンティティのリストを返却するか、PagingAndSortingRepository または JpaRepository が使用されている場合はページを返します。

  • GET /fruits/:id - IDに基づいてエンティティを返却します。

  • POST /fruits - 新しいエンティティを作成します。

  • PUT /fruits/:id - 既存のエンティティを更新するか、指定されたIDで新しいエンティティを作成します(エンティティ定義で許可されている場合)。

  • DELETE /fruits/:id - ID に基づいてエンティティを削除します。

サポートされているデータタイプは、 application/jsonapplication/hal+json の2種類です。デフォルトでは前者が使用されますが、 Accept のヘッダーでどちらを使用するか指定することを強くお勧めします。

大量のエンティティの公開

データベースに大量のエンティティが含まれている場合、それらをすべて一度に返すのは得策ではないかもしれません。 PagingAndSortingRepository では、 spring-data-rest エクステンションを使って、データをチャンク単位でアクセスすることができます。

So, you can extend the PagingAndSortingRepository:

package org.acme.spring.data.rest;

import org.springframework.data.repository.PagingAndSortingRepository;

public interface FruitsRepository extends CrudRepository<Fruit, Long>, PagingAndSortingRepository<Fruit, Long> {
}

これで GET /fruits は、 sortpagesize という3つの新しいクエリパラメータを受け付けるようになりました。

クエリーパラメーター 説明 デフォルト値 値の例

sort

list操作で返されたエンティティをソートします

""

?sort=name (ascending name), ?sort=name,-color (昇順の名前と降順の色)

page

0始まりのインデックスのページ番号。無効な値は0と解釈されます。

0

0, 11, 100

size

ページサイズ。最小値は1で、それ以下の値は1と解釈されます。

20

1, 11, 100

ページングされたレスポンスの場合、 spring-data-rest は、他のページにアクセスするために使用できるリンクヘッダーのセット(first、previous、next、last)も返します。

Additionally, rather than extending both PagingAndSortingRepository and CrudRepository, you can use JpaRepository, which is a higher-level abstraction tailored for JPA. Since JpaRepository already extends both PagingAndSortingRepository and CrudRepository, it can replace CrudRepository directly.

package org.acme.spring.data.rest;

import org.springframework.data.repository.PagingAndSortingRepository;

public interface FruitsRepository extends JpaRepository<Fruit, Long> {
}

エンドポイント生成の微調整

これにより、どのメソッドを公開し、どのパスを使ってアクセスするかを指定できます。Spring Data RESTには @RepositoryRestResource@RestResource という2つのアノテーションがあります。 spring-data-rest エクステンションはこれらのアノテーションの exported, path collectionResourceRel 属性をサポートしています。

例えば、フルーツリポジトリは /my-fruits のパスでアクセスでき、 GET の操作しかできないようにする必要があるとします。このような場合、 FruitsRepository は次のようになります:

package org.acme.spring.data.rest;

import java.util.Optional;

import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;

@RepositoryRestResource(exported = false, path = "/my-fruits")
public interface FruitsRepository extends CrudRepository<Fruit, Long> {

    @RestResource(exported = true)
    Optional<Fruit> findById(Long id);

    @RestResource(exported = true)
    Iterable<Fruit> findAll();
}

spring-data-rest は、データアクセスにリポジトリメソッドのサブセットのみを使用します。RESTエンドポイントをカスタマイズするためには、正しいメソッドにアノテーションを付けることが重要です。

REST operation CrudRepository PagingAndSortingRepository と JpaRepository

IDによるGet

Optional<T> findById(ID id)

Optional<T> findById(ID id)

List

Iterable<T> findAll()

Page<T> findAll(Pageable pageable)

Create

<S extends T> S save(S entity)

<S extends T> S save(S entity)

Update

<S extends T> S save(S entity)

<S extends T> S save(S entity)

Delete

void deleteById(ID id)

void deleteById(ID id)

エンドポイントのセキュア化

このエクステンションは、リソースインターフェイスに定義されているパッケージ jakarta.annotation.security 内の Security アノテーションを自動的に使用します。

import jakarta.annotation.security.DenyAll;
import jakarta.annotation.security.RolesAllowed;

@DenyAll
public interface FruitResource extends CrudRepository<Fruit, Long> {
    @RolesAllowed("superuser")
    Iterable<Fruit> findAll();
}

なお、この機能は、このエクステンションがフード下で使用しているREST Data with Panacheエクステンションによって提供されています。そのため、純粋なSpring Bootアプリケーションでは、同じように動作しないかもしれません。

現在サポートされていない機能

  • 上記のリポジトリメソッドのみがサポートされています。その他の標準的なメソッドやカスタムメソッドはサポートされていません。

  • exposed, path, collectionResourceRel のアノテーションプロパティにのみ対応しています。

重要な技術的注意点

Quarkus での Spring サポートは、Spring アプリケーションコンテキストを開始せず、Spring インフラストラクチャークラスも実行されないことに注意してください。Spring クラスとアノテーションは、メタデータの読み取りにのみ使用されるか、ユーザーコードメソッドのリターンタイプまたはパラメータータイプとして使用されます。

関連コンテンツ