The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Spring Web APIのためのQuarkus エクステンション

RESTエンドポイントの定義には、Jakarta REST(旧称JAX-RS)アノテーションを使用することが推奨されていますが、Quarkusは、 spring-web エクステンションという形でSpring Webの互換性レイヤーを提供しています。

このガイドでは、よく知られているSpring Webアノテーションを利用して、QuarkusアプリケーションでRESTfulサービスを定義する方法を説明します。

前提条件

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

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

  • 約15分

  • IDE

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

  • Apache Maven 3.9.6

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

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

ソリューション

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

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

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

Mavenプロジェクトの作成

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

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

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

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

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.8.1:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=spring-web-quickstart \
    -Dextensions='spring-web,resteasy-reactive-jackson' \
    -DnoCode
cd spring-web-quickstart

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

Windowsユーザーの場合:

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

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

このコマンドは、プロジェクトを生成し、 spring-web エクステンションをインポートします。

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

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

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

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-spring-web</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-spring-web")
implementation("io.quarkus:quarkus-resteasy-reactive-jackson")

quarkus-spring-web は、 quarkus-resteasy-jackson または quarkus-resteasy-reactive-jackson のいずれかで補完されないと動作しません。

GreetingController

RESTエンドポイントを定義するためのSpring Webアノテーションを持つコントローラである src/main/java/org/acme/spring/web/GreetingController.java ファイルを以下のように作成します:

package org.acme.spring.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/greeting")
public class GreetingController {

    @GetMapping
    public String hello() {
        return "hello";
    }
}

GreetingControllerTest

なお、コントローラのテストも作成されています:

package org.acme.spring.web;

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

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class GreetingControllerTest {

    @Test
    public void testHelloEndpoint() {
        given()
          .when().get("/greeting")
          .then()
             .statusCode(200)
             .body(is("hello"));
    }

}

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

アプリケーションを次のように実行します:

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

ブラウザで http://localhost:8080/greeting を開きます。

結果は {"message": "hello"} のようになります。

アプリケーションをネイティブ実行可能ファイルとして実行する

以下を使用して、ネイティブ実行可能ファイルを生成することができます:

コマンドラインインタフェース
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.package.type=native

JSONを返すエンドポイントでその先へ

上の GreetingController は、非常にシンプルなエンドポイントの例でした。しかし、多くの場合、JSONコンテンツを返さなければなりません。次の例では、Spring RestControllerを使用して、これを実現しています。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/greeting")
public class GreetingController {

    @GetMapping("/{name}")
    public Greeting hello(@PathVariable(name = "name") String name) {
        return new Greeting("hello " + name);
    }

    public static class Greeting {
        private final String message;

        public Greeting(String message) {
            this.message = message;
        }

        public String getMessage(){
            return message;
        }
    }
}

対応するテストは次のようになります:

package org.acme.spring.web;

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

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class GreetingControllerTest {

    @Test
    public void testHelloEndpoint() {
        given()
          .when().get("/greeting/quarkus")
          .then()
            .statusCode(200)
            .body("message", is("hello quarkus"));
    }

}

なお、QuarkusでSpring Webサポートを使用する場合、 Jacksonは自動的にクラスパスに追加され、適切に設定されます。

OpenAPIとSwagger-UIの追加

quarkus-smallrye-openapi エクステンションを使うことで、 OpenAPISwagger-UIのサポートを追加することができます。

このコマンドを実行してエクステンションを追加:

./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-smallrye-openapi"

これにより、 pom.xml に以下が追加されます:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>

これだけでRESTエンドポイントから基本的なOpenAPIスキーマドキュメントを生成するのには十分です:

curl http://localhost:8080/q/openapi

生成されたOpenAPIスキーマのドキュメントが表示されます:

---
openapi: 3.0.1
info:
  title: Generated API
  version: "1.0"
paths:
  /greeting:
    get:
      responses:
        "200":
          description: OK
          content:
            '*/*':
              schema:
                type: string
  /greeting/{name}:
    get:
      parameters:
      - name: name
        in: path
        required: true
        schema:
          type: string
      responses:
        "200":
          description: OK
          content:
            'application/json':
              schema:
                $ref: '#/components/schemas/Greeting'
components:
  schemas:
    Greeting:
      type: object
      properties:
        message:
          type: string

OpenAPI ガイド も参照してください。

MicroProfile OpenAPIアノテーションの追加

MicroProfile OpenAPIを使用して、スキーマをより良く文書化することができます。例えば、 GreetingController のクラスレベルに以下を追加します:

@OpenAPIDefinition(
    info = @Info(
        title="Greeting API",
        version = "1.0.1",
        contact = @Contact(
            name = "Greeting API Support",
            url = "http://exampleurl.com/contact",
            email = "techsupport@example.com"),
        license = @License(
            name = "Apache 2.0",
            url = "https://www.apache.org/licenses/LICENSE-2.0.html"))
)

そして、エンドポイントをこのように記述します:

@Tag(name = "Hello", description = "Just say hello")
@GetMapping(produces=MediaType.TEXT_PLAIN_VALUE)
public String hello() {
    return "hello";
}

@GetMapping(value = "/{name}", produces=MediaType.APPLICATION_JSON_VALUE)
@Tag(name = "Hello to someone", description = "Just say hello to someone")
public Greeting hello(@PathVariable(name = "name") String name) {
    return new Greeting("hello " + name);
}

これにより、このOpenAPIスキーマが生成されます:

---
openapi: 3.0.1
info:
  title: Greeting API
  contact:
    name: Greeting API Support
    url: http://exampleurl.com/contact
    email: techsupport@example.com
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
  version: 1.0.1
tags:
- name: Hello
  description: Just say hello
- name: Hello to someone
  description: Just say hello to someone
paths:
  /greeting:
    get:
      tags:
      - Hello
      responses:
        "200":
          description: OK
          content:
            '*/*':
              schema:
                type: string
  /greeting/{name}:
    get:
      tags:
      - Hello to someone
      parameters:
      - name: name
        in: path
        required: true
        schema:
          type: string
      responses:
        "200":
          description: OK
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/Greeting'
components:
  schemas:
    Greeting:
      type: object
      properties:
        message:
          type: string

Swagger UIの使用

Swagger UIは、 Dev または Test モードで実行するとデフォルトで含まれており、オプションで Prod モードに追加することができます。詳細は Swagger UI ガイドをご覧ください。

localhost:8080/q/swagger-ui/ に移動すると、Swagger UIの画面が表示されます:

Swagger UI

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

Quarkusは現在、Spring Webが提供する機能のサブセットをサポートしています。具体的には、QuarkusはSpring WebのREST関連の機能をサポートしています( @Controller の代わりに @RestController を考えてみてください)。

アノテーション

下の表は、サポートされているアノテーションをまとめたものです:

Table 1. サポートされているSpring Webアノテーション
名前 コメント

@RestController

@RequestMapping

@GetMapping

@PostMapping

@PutMapping

@DeleteMapping

@PatchMapping

@RequestParam

@RequestHeader

@MatrixVariable

@PathVariable

@CookieValue

@RequestBody

@ResponseStatus

@ExceptionHandler

コントローラごとではなく、@RestControllerAdviceクラスでのみ使用可能です

@RestControllerAdvice

サポートされているのは@ExceptionHandler機能のみです

コントローラメソッドの戻り値の型

以下のメソッドの戻り値の型がサポートされています:

  • プリミティブ型

  • 文字列 (リテラルとして使用されます。Spring MVC ビューのサポートはありません)

  • JSON 経由でシリアライズされる POJO クラス

  • org.springframework.http.ResponseEntity

コントローラメソッドのパラメーターの型

前の表にある適切なSpring Webアノテーションでアノテーションできるメソッドパラメータに加えて、 jakarta.servlet.http.HttpServletRequestjakarta.servlet.http.HttpServletResponse もサポートされています。ただし、これを機能させるためには、 quarkus-undertow の依存関係を追加する必要があります。

例外ハンドラーメソッドの戻り値の型

以下のメソッドの戻り値の型がサポートされています:

  • org.springframework.http.ResponseEntity

  • java.util.Map

Spring ExceptionHandler javadoc に記載されているその他の戻り値型はサポートされていません。

例外ハンドラーメソッドのパラメーターの型

以下のパラメーターの型がサポートされています(順不同):

  • 例外の引数:一般的な Exception として、またはより具体的な例外として宣言されています。これは、アノテーション自体が value() を使って例外の型を狭めていない場合、マッピングのヒントにもなります。

  • リクエストおよび/またはレスポンスオブジェクト(通常、サーブレットAPIからのもの)。ServletRequest / HttpServletRequest のように、 特定のリクエスト/レスポンス型を選択することができます。Servlet APIを使用するには、 quarkus-undertow の依存関係を追加する必要があります。

Spring ExceptionHandler javadoc に記載されているその他のパラメーターの型はサポートされていません。

重要な技術的注意点

Quarkus での Spring サポートは、Spring Application Context を開始せず、Spring インフラストラクチャークラスも実行しないことに注意してください。Spring クラスとアノテーションは、メタデータの読み取りにのみ使用されるか、ユーザーコードメソッドの戻り値の型またはパラメーター型として使用されます。エンドユーザーにとってそれが意味することは、任意の Spring ライブラリーを追加しても効果がないということです。さらに、Spring インフラストラクチャークラス (たとえば、org.springframework.beans.factory.config.BeanPostProcessor など) は実行されません。

変換テーブル

以下の表は、Spring WebのアノテーションをJakarta RESTのアノテーションに変換する方法を示しています。

Spring Jakarta REST コメント

@RestController

Jakarta RESTには同等のものはありません。クラスを@Pathでアノテーションするので十分です。

@RequestMapping(path="/api")

@Path("/api")

@RequestMapping(consumes="application/json")

@Consumes("application/json")

@RequestMapping(produce="application/json")

@Produces("application/json")

@RequestParam

@QueryParam

@PathVariable

@PathParam

@RequestBody

Jakarta RESTに同等のものはありません。リクエスト本体に対応するメソッドパラメータは、Jakarta RESTではアノテーションを必要とせずハンドリングされます。

@RestControllerAdvice

Jakarta RESTに同等のものはありません。

@ResponseStatus

Jakarta RESTに同等のものはありません。

@ExceptionHandler

Jakarta RESTには同等のアノテーションはありません。例外の処理には jakarta.ws.rs.ext.ExceptionMapper の実装によってハンドリングされます。

関連コンテンツ