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

RESTEasy Classic

このガイドは、 Quarkus 2.8 までデフォルトの JAX-RS 実装として使用されていた RESTEasy Classic についてのガイドです。

現在では、従来のブロック型ワークロードとリアクティブ型ワークロードを同様にサポートする RESTEasy Reactive の使用が推奨されています。 RESTEasy Reactive の詳細については、 入門編の REST JSON ガイドまたは詳細な RESTEasy Reactive ガイドを参照してください。

RESTEasy Classic をベースにした REST クライアント( JSON のサポートを含む)が必要な場合は、別のガイドを参照してください。

アーキテクチャ

このガイドで開発するアプリケーションは非常にシンプルです: ユーザーはフォームを使用してリストに要素を追加することができ、リストが更新されます。

ブラウザとサーバー間の情報はすべて JSON 形式になっています。

Mavenプロジェクトの作成

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

コマンドラインインタフェース
quarkus create app org.acme:rest-json-quickstart \
    --stream=2.16 \
    --extension='resteasy-jackson' \
    --no-code
cd rest-json-quickstart

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

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

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.16.12.Final:create \
    -DplatformVersion=2.16 \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=rest-json-quickstart \
    -Dextensions='resteasy-jackson' \
    -DnoCode
cd rest-json-quickstart

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

このコマンドは、 RESTEasy/JAX-RS および Jackson エクステンションをインポートする新しいプロジェクトを生成し、特に次の依存関係を追加します。

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

ユーザーエクスペリエンスを向上させるために、Quarkusは3つのJackson Java 8モジュール を登録しているので、手動で登録する必要はありません。

Quarkus は JSON-B もサポートしているため、 Jackson よりも JSON-B を利用したい場合は、代わりに RESTEasy JSON-B エクステンションを依存関係に持つプロジェクトを作成することができます。

コマンドラインインタフェース
quarkus create app org.acme:rest-json-quickstart \
    --stream=2.16 \
    --extension='resteasy-jsonb' \
    --no-code
cd rest-json-quickstart

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

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

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.16.12.Final:create \
    -DplatformVersion=2.16 \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=rest-json-quickstart \
    -Dextensions='resteasy-jsonb' \
    -DnoCode
cd rest-json-quickstart

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

このコマンドは、 RESTEasy/JAX-RS および JSON-B エクステンションをインポートする新しいプロジェクトを生成し、特に次の依存関係を追加します。

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

初めてのJSON RESTサービスの作成

この例では、果物のリストを管理するアプリケーションを作成します。

まず、以下のように Fruit Bean を作成してみましょう。

package org.acme.rest.json;

public class Fruit {

    public String name;
    public String description;

    public Fruit() {
    }

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

派手なことは何もありません。注意すべき重要なことは、デフォルトのコンストラクタを持つことはJSONシリアライズレイヤーで必須であるということです。

次に、 org.acme.rest.json.FruitResource クラスを以下のように作成します。

package org.acme.rest.json;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Set;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;

@Path("/fruits")
public class FruitResource {

    private Set<Fruit> fruits = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>()));

    public FruitResource() {
        fruits.add(new Fruit("Apple", "Winter fruit"));
        fruits.add(new Fruit("Pineapple", "Tropical fruit"));
    }

    @GET
    public Set<Fruit> list() {
        return fruits;
    }

    @POST
    public Set<Fruit> add(Fruit fruit) {
        fruits.add(fruit);
        return fruits;
    }

    @DELETE
    public Set<Fruit> delete(Fruit fruit) {
        fruits.removeIf(existingFruit -> existingFruit.name.contentEquals(fruit.name));
        return fruits;
    }
}

実装は非常に簡単で、 JAX-RS のアノテーションを使ってエンドポイントを定義するだけです。

Fruit オブジェクトは、プロジェクトの初期化時に選択したエクステンションに応じて、 JSON-B または Jackson によって自動的にシリアライズ/デシリアライズされます。

quarkus-resteasy-jacksonquarkus-resteasy-jsonb などの JSON エクステンションがインストールされている場合、メディアタイプが @Produces@Consumes アノテーションで明示的に設定されていない限り、Quarkus はほとんどの戻り値に application/json メディアタイプをデフォルトで使用します( StringFile などのよく知られたタイプには例外があり、それぞれ text/plainapplication/octet-stream がデフォルトとなっています)。

デフォルトでJSONを使用したくない場合は、 quarkus.resteasy-json.default-json=false を設定すると、デフォルトは自動ネゴシエーションに戻ります。これを設定した場合、JSON を使用するためには @Produces(MediaType.APPLICATION_JSON)@Consumes(MediaType.APPLICATION_JSON) をエンドポイントに追加する必要があります。

JSON のデフォルトに頼らない場合は、エンドポイントに @Produces@Consumes のアノテーションを付けて、期待されるコンテンツタイプを正確に定義することを強くお勧めします。これにより、ネイティブ実行可能ファイルに含まれる JAX-RS プロバイダ (コンバータとみなすことができます) の数を絞り込むことができます。

JSON サポートの設定

Jackson

Quarkusでは、CDI経由で取得した(そしてQuarkusのエクステンションによって消費される)デフォルトのJackson ObjectMapper は、未知のプロパティーを無視するように設定されています( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 機能を無効にすることで)。

application.propertiesquarkus.jackson.fail-on-unknown-properties=true を設定するか、 クラスごとに @JsonIgnoreProperties(ignoreUnknown = false) を設定することで、Jackson のデフォルトの動作を復元することができます。

さらに、 ObjectMapper 、日付と時刻をISO-8601でフォーマットするように設定されています( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS の機能を無効にすることで)。

application.propertiesquarkus.jackson.fail-on-unknown-properties=true を設定するか、 @JsonIgnoreProperties(ignoreUnknown = false) を経由してクラスごとに設定することで、Jackson のデフォルトの動作を復元することができます。

また、Quarkusは、CDI Bean を介して、様々なJackson設定を非常に簡単に設定することができます。最も単純な(そして推奨される)アプローチは、 io.quarkus.jackson.ObjectMapperCustomizer 型の CDI Bean を定義し、その中で、Jackson の設定を適用することです。

カスタムモジュールを登録する必要がある場合の例は次のようになります。

import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import javax.inject.Singleton;

@Singleton
public class RegisterCustomModuleCustomizer implements ObjectMapperCustomizer {

    public void customize(ObjectMapper mapper) {
        mapper.registerModule(new CustomModule());
    }
}

ユーザーは、選択すれば自分の ObjectMapper Beanを提供することもできます。この場合、 ObjectMapper を生成する CDI プロデューサの中で、すべての io.quarkus.jackson.ObjectMapperCustomizer Bean を手動で注入して適用することが非常に重要です。これを怠ると、様々なエクステンションによって提供される Jackson 固有のカスタマイズが適用されなくなります。

import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;

import javax.enterprise.inject.Instance;
import javax.inject.Singleton;

public class CustomObjectMapper {

    // Replaces the CDI producer for ObjectMapper built into Quarkus
    @Singleton
    ObjectMapper objectMapper(Instance<ObjectMapperCustomizer> customizers) {
        ObjectMapper mapper = myObjectMapper(); // Custom `ObjectMapper`

        // Apply all ObjectMapperCustomizer beans (incl. Quarkus)
        for (ObjectMapperCustomizer customizer : customizers) {
            customizer.customize(mapper);
        }

        return mapper;
    }
}

JSON-B

上記のように、Quarkusでは、 quarkus-resteasy-jsonb エクステンションを使用することで、Jacksonの代わりにJSON-Bを使用するオプションを提供しています。

前項と同様のアプローチで、 io.quarkus.jsonb.JsonbConfigCustomizer beanを使用してJSON-Bを設定することができます。

例えば、 FooSerializer という名前のカスタムシリアライザを com.example.Foo タイプで JSON-B で登録する必要がある場合、以下のような Bean を追加すれば十分です。

import io.quarkus.jsonb.JsonbConfigCustomizer;
import javax.inject.Singleton;
import javax.json.bind.JsonbConfig;
import javax.json.bind.serializer.JsonbSerializer;

@Singleton
public class FooSerializerRegistrationCustomizer implements JsonbConfigCustomizer {

    public void customize(JsonbConfig config) {
        config.withSerializers(new FooSerializer());
    }
}

より高度なオプションとしては、 javax.json.bind.JsonbConfig ( Dependent スコープ付き)の Bean を直接提供するか、極端な場合には javax.json.bind.Jsonb ( Singleton スコープ付き)のタイプの Bean を提供することが考えられます。後者のアプローチを利用する場合は、 javax.json.bind.Jsonb を生成する CDI プロデューサに io.quarkus.jsonb.JsonbConfigCustomizer Bean をすべて手動で注入して適用することが非常に重要です。これを怠ると、様々なエクステンションによって提供される JSON-B 固有のカスタマイズが適用されなくなります。

import io.quarkus.jsonb.JsonbConfigCustomizer;

import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Instance;
import javax.json.bind.JsonbConfig;

public class CustomJsonbConfig {

    // Replaces the CDI producer for JsonbConfig built into Quarkus
    @Dependent
    JsonbConfig jsonConfig(Instance<JsonbConfigCustomizer> customizers) {
        JsonbConfig config = myJsonbConfig(); // Custom `JsonbConfig`

        // Apply all JsonbConfigCustomizer beans (incl. Quarkus)
        for (JsonbConfigCustomizer customizer : customizers) {
            customizer.customize(config);
        }

        return config;
    }
}

HAL 標準は、ウェブリンクを表現するためのシンプルなフォーマットです。

HAL のサポートを有効にするには、 quarkus-hal エクステンションをプロジェクトに追加します。また、 HAL は JSON サポートを必要とするため、 quarkus-resteasy-jsonb または quarkus-resteasy-jackson のいずれかのエクステンションモジュールを追加する必要があります。

Table 1. テーブルコンテキストオブジェクト
GAV 使用方法

io.quarkus:quarkus-hal

HAL

エクステンションを追加したら、次は REST リソースにアノテーションを付け、メディアタイプ application/hal+json (または RestMediaType.APPLICATION_HAL_JSON を使用) を生成できるようにします。例えば、以下のようになります。

@Path("/records")
public class RecordsResource {

    @GET
    @Produces({ MediaType.APPLICATION_JSON, "application/hal+json" })
    @LinkResource(entityClassName = "org.acme.Record", rel = "list")
    public List<TestRecord> getAll() {
        // ...
    }

    @GET
    @Path("/first")
    @Produces({ MediaType.APPLICATION_JSON, "application/hal+json" })
    @LinkResource(rel = "first")
    public TestRecord getFirst() {
        // ...
    }
}

これで、エンドポイント /records/records/first は、メディアタイプ jsonhal+json の両方を受け入れ、HAL 形式のレコードを表示します。

例えば、 curl を使用して /records エンドポイントを呼び出してレコードのリストを返す場合、HAL 形式は次のようになります。

& curl -H "Accept:application/hal+json" -i localhost:8080/records
{
    "_embedded": {
        "items": [
            {
                "id": 1,
                "slug": "first",
                "value": "First value",
                "_links": {
                    "list": {
                        "href": "http://localhost:8081/records"
                    },
                    "first": {
                        "href": "http://localhost:8081/records/first"
                    }
                }
            },
            {
                "id": 2,
                "slug": "second",
                "value": "Second value",
                "_links": {
                    "list": {
                        "href": "http://localhost:8081/records"
                    },
                    "first": {
                        "href": "http://localhost:8081/records/first"
                    }
                }
            }
        ]
    },
    "_links": {
        "list": {
            "href": "http://localhost:8081/records"
        }
    }
}

When we call a resource /records/first that returns only one instance, then the output is:

& curl -H "Accept:application/hal+json" -i localhost:8080/records/first
{
    "id": 1,
    "slug": "first",
    "value": "First value",
    "_links": {
        "list": {
            "href": "http://localhost:8081/records"
        },
        "first": {
            "href": "http://localhost:8081/records/first"
        }
    }
}

フロントエンドの作成

ここで、 FruitResource .Quarkusと対話するための簡単なウェブページを追加してみましょう。Quarkusは、 META-INF/resources ディレクトリーの下にある静的リソースを自動的に提供します。 src/main/resources/META-INF/resources ディレクトリーに、この fruits.html ファイルの内容を含む fruits.html ファイルを追加します。

これで、REST サービスと対話できるようになりました。

  • 以下のように Quarkus を起動します。

    コマンドラインインタフェース
    quarkus dev
    Maven
    ./mvnw quarkus:dev
    Gradle
    ./gradlew --console=plain quarkusDev
  • ブラウザで http://localhost:8080/fruits.html を開きます。

  • フォームを使って新しいフルーツをリストに追加します。

ネイティブ実行可能ファイルの構築

以下のコマンドでネイティブ実行可能ファイルをビルドすることができます。

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

実行は簡単で、 ./target/rest-json-quickstart-1.0-SNAPSHOT-runner を実行するだけです。

その後、ブラウザで http://localhost:8080/fruits.html を開いてアプリケーションを使用します。

シリアライゼーションについて

JSONシリアライズライブラリは、Javaのリフレクションを使用してオブジェクトのプロパティーを取得してシリアライズします。

GraalVMでネイティブ実行可能ファイルを使用する場合、リフレクションで使用されるすべてのクラスを登録する必要があります。良いニュースは、Quarkusがほとんどの場合、その作業を代行してくれるということです。これまでのところ、 Fruit でさえ、リフレクトを使用するためのクラスを登録しておらず、すべてが正常に動作しています。

Quarkusは、RESTメソッドからシリアライズされた型を推論することができる場合に、何らかのマジックを実行します。以下のようなRESTメソッドがある場合、Quarkusは、 Fruit がシリアライズされると判断します。

@GET
public List<Fruit> list() {
    // ...
}

Quarkusは、ビルド時にRESTメソッドを分析することで、自動的にそのような処理を行ってくれます。

JAX-RSの世界では、 Response オブジェクトを使用するのがもう一つの一般的なパターンです。 Response にはいくつかの素晴らしい特典があります。

  • メソッドで何が起こるかによって異なるエンティティータイプを返すことができます (例えば LegumeError )。

  • Response の属性を設定することができます (エラーが発生した時にステータスを知ることができます)。

RESTメソッドは次のようになります。

@GET
public Response list() {
    // ...
}

Response に含まれるタイプは情報がないため、Quarkusがビルド時に判断することはできません。この場合、Quarkusは必要なクラスを自動的に反映登録することができません。

これが次のセクションにつながります。

レスポンスの利用

Fruit クラスと同じモデルに従って、JSON としてシリアライズされる Legume クラスを作成してみましょう。

package org.acme.rest.json;

public class Legume {

    public String name;
    public String description;

    public Legume() {
    }

    public Legume(String name, String description) {
        this.name = name;
        this.description = description;
    }
}

それでは、マメ科植物のリストを返すメソッドを一つだけ持つ LegumeResource REST サービスを作成してみましょう。

このメソッドは Response を返し、 Legume のリストではありません。

package org.acme.rest.json;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/legumes")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class LegumeResource {

    private Set<Legume> legumes = Collections.synchronizedSet(new LinkedHashSet<>());

    public LegumeResource() {
        legumes.add(new Legume("Carrot", "Root vegetable, usually orange"));
        legumes.add(new Legume("Zucchini", "Summer squash"));
    }

    @GET
    public Response list() {
        return Response.ok(legumes).build();
    }
}

ここで、マメ科植物のリストを表示するための簡単なウェブページを追加してみましょう。 src/main/resources/META-INF/resources ディレクトリーに、この legumes.html ファイルの内容を含む legumes.html ファイルを追加します。

ブラウザーを開いて http://localhost:8080/legumes.html にアクセスすると、マメ科植物のリストが表示されます。

興味深い部分は、アプリケーションをネイティブ実行可能ファイルとして実行するときに始まります。

  • 以下でネイティブ実行可能ファイルを作成します。

    コマンドラインインタフェース
    quarkus build --native
    Maven
    ./mvnw install -Dnative
    Gradle
    ./gradlew build -Dquarkus.package.type=native
  • ./target/rest-json-quickstart-1.0-SNAPSHOT-runner で実行します

  • ブラウザーを起動し、 http://localhost:8080/legumes.html にアクセスします。

そこには豆類はありません。

上記のように、問題は Quarkus が、 REST エンドポイントを分析することで Legume クラスが何らかのリフレクションを必要とすることを判断できなかったことです。 JSON シリアライズライブラリーは、 Legume のフィールドのリストを取得しようとすると空のリストを取得するため、フィールドのデータをシリアライズしません。

現時点では、JSON-BやJacksonがクラスのフィールドのリストを取得しようとしたときに、そのクラスがリフレクションに登録されていない場合、例外はスローされません。GraalVMは単に空のフィールドのリストを返します。

うまくいけば、将来的にはこれが変化して、エラーがより明白になるでしょう。

Legume クラスに @RegisterForReflection アノテーションを追加することで、手動で Legume を リフレクション用に登録することができます。

import io.quarkus.runtime.annotations.RegisterForReflection;

@RegisterForReflection
public class Legume {
    // ...
}
@RegisterForReflection アノテーションは、ネイティブコンパイル時にクラスとそのメンバーを保持するよう Quarkus に指示します。 @RegisterForReflection アノテーションの詳細については、 ネイティブアプリケーションのヒントのページを参照してください。

それを実行して、今までと同じ手順を踏んでみましょう。

  • Ctrl+C を叩いてアプリケーションを停止させる

  • 以下でネイティブ実行可能ファイルを作成します。

    コマンドラインインタフェース
    quarkus build --native
    Maven
    ./mvnw install -Dnative
    Gradle
    ./gradlew build -Dquarkus.package.type=native
  • ./target/rest-json-quickstart-1.0-SNAPSHOT-runner で実行します

  • ブラウザーを起動し、 http://localhost:8080/legumes.html にアクセスします。

今回はマメ科の一覧が表示されました。

リアクティブであること

リアクティブなワークロードには、常に RESTEasy Reactive を使用してください。

非同期処理を処理するために リアクティブ型 を返すことができます。Quarkusでは、リアクティブで非同期なコードを書くために Mutiny の使用を推奨しています。

Mutiny と RESTEasy を統合するには、 quarkus-resteasy-mutiny 依存関係をプロジェクトに追加する必要があります。

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

そして、エンドポイントは UniMulti のインスタンスを返すことができます。

@GET
@Path("/{name}")
public Uni<Fruit> getOne(@PathParam String name) {
    return findByName(name);
}

@GET
public Multi<Fruit> getAll() {
    return findAll();
}

単一の結果がある場合は Uni を使用します。 Multi は、非同期的に放出される可能性のある複数の項目がある場合に使用します。

UniResponse を使用して、非同期 HTTP レスポンスを返すことができます: Uni<Response> .

Mutiny についての詳細は、 Mutiny - 直感的なリアクティブプログラミングライブラリー に記載されています。

HTTP フィルターとインターセプター

HTTP リクエストとレスポンスの両方とも、それぞれ ContainerRequestFilter または ContainerResponseFilter の実装を提供することで、 インターセプトすることができます。これらのフィルタは、メッセージに関連付けられたメタデータを処理するのに適しています。HTTP ヘッダ、クエリパラメーター、メディアタイプ、その他のメタデータです。また、ユーザーがエンドポイントにアクセスする権限を持っていない場合など、リクエスト処理を中止する機能も持っています。

ContainerRequestFilter を使用して、サービスにロギング機能を追加してみましょう。 ContainerRequestFilter を実装して、 @Provider アノテーションをつけることで実現できます。

package org.acme.rest.json;

import io.vertx.core.http.HttpServerRequest;
import org.jboss.logging.Logger;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;

@Provider
public class LoggingFilter implements ContainerRequestFilter {

    private static final Logger LOG = Logger.getLogger(LoggingFilter.class);

    @Context
    UriInfo info;

    @Context
    HttpServerRequest request;

    @Override
    public void filter(ContainerRequestContext context) {

        final String method = context.getMethod();
        final String path = info.getPath();
        final String address = request.remoteAddress().toString();

        LOG.infof("Request %s %s from IP %s", method, path, address);
    }
}

これで、RESTメソッドが呼び出されるたびに、リクエストがコンソールにログとして記録されるようになりました。

2019-06-05 12:44:26,526 INFO  [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request GET /legumes from IP 127.0.0.1
2019-06-05 12:49:19,623 INFO  [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request GET /fruits from IP 0:0:0:0:0:0:0:1
2019-06-05 12:50:44,019 INFO  [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request POST /fruits from IP 0:0:0:0:0:0:0:1
2019-06-05 12:51:04,485 INFO  [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request GET /fruits from IP 127.0.0.1

CORS フィルター

クロスオリジンリソース共有 (CORS)は、ウェブページ上の制限されたリソースを、最初のリソースが提供されたドメイン以外の別のドメインから要求できるようにするメカニズムです。

Quarkus には、 CORS フィルターが付属しています。使用方法については、 HTTP リファレンスドキュメント を参照してください。

GZipのサポート

QuarkusにはGZipサポートが搭載されています(デフォルトでは有効になっていませんが)。以下の設定ノブを使用して、GZipサポートを設定できます。

quarkus.resteasy.gzip.enabled=true (1)
quarkus.resteasy.gzip.max-input=10M (2)
1 Gzipサポートを有効にします。
2 デフレーションされたリクエストボディの上限を設定します。これは、リーチを制限することで潜在的な攻撃を緩和するのに便利です。既定値は 10M です。この設定オプションは、以下の形式の文字列を認識します(正規表現で表示されます): [0-9]+[KkMmGgTtPpEeZzYy]? .サフィックスが指定されていない場合は、バイトとみなします。

GZip サポートが有効になったら、エンドポイントメソッドに @org.jboss.resteasy.annotations.GZIP アノテーションを追加することで、エンドポイントで使用することができます。

設定プロパティー quarkus.http.enable-compression は、RESTEasy Classic エンドポイントの圧縮サポートに影響を与えません。

マルチパートサポート

RESTEasyは RESTEasy Multipart Provider を介してマルチパートをサポートしています。

Quarkusは、 quarkus-resteasy-multipart というエクステンションを提供しています。

このエクステンションは、デフォルトの文字セットが US-ASCII ではなく UTF-8 であるため、RESTEasy のデフォルトの動作とは若干異なります。

この動作は、以下の設定プロパティーで設定できます。

ビルド時に固定される設定プロパティ - 他のすべての設定プロパティは実行時にオーバーライド可能

Configuration property

タイプ

デフォルト

Default charset. Note that the default value is UTF-8 which is different from RESTEasy’s default value US-ASCII.

Environment variable: QUARKUS_RESTEASY_MULTIPART_INPUT_PART_DEFAULT_CHARSET

Show more

Charset

UTF-8

The default content-type.

Environment variable: QUARKUS_RESTEASY_MULTIPART_INPUT_PART_DEFAULT_CONTENT_TYPE

Show more

string

text/plain

サーブレットとの互換性

Quarkusでは、RESTEasyはVert.x HTTPサーバーの上で直接実行するか、サーブレットに依存している場合はUndertowの上で実行することができます。

その結果、 HttpServletRequest のような特定のクラスが常にインジェクションに利用できるわけではありません。この特定のクラスのほとんどのユースケースは、リモートクライアントの IP を取得することを除いて、JAX-RS と同等のものでカバーされています。RESTEasy には、インジェクション可能な代替 API が付属しています。 HttpRequest これは以下のメソッドを持っています。 getRemoteAddress() そして getRemoteHost() を解決するために、この問題を解決します。

RESTEasy と RESTクライアントのやりとり

Quarkus では、 RESTEasy エクステンションと REST Client エクテンションは同じインフラストラクチャーを共有しています。この考察の重要な結果の1つは、 JAX-RS の意味においての同じプロバイダーリストを共有していることです。

例えば、 WriterInterceptor を宣言した場合、デフォルトではサーバーの呼び出しとクライアントの呼び出しの両方をインターセプトしますが、これは望ましい動作ではないかもしれません。

しかし、このデフォルトの動作を変更してプロバイダを制約することができます。

  • プロバイダに @ConstrainedTo(RuntimeType.SERVER) アノテーションを追加することで、 サーバー コールのみを考慮します。

  • プロバイダに @ConstrainedTo(RuntimeType.CLIENT) アノテーションを追加することで、 クライアント コールのみを考慮します。

Jakarta EE 開発との違い

Application クラスは不要

Application のアプリケーションが提供するサブクラスによる設定もサポートされていますが、必須ではありません。

単一のJAX-RSアプリケーションのみ

JAX-RS(およびRESTeasy)が標準のサーブレットコンテナーで実行されているのとは対照的に、Quarkusは単一のJAX-RSアプリケーションのデプロイのみをサポートしています。複数のJAX-RS Application クラスが定義されている場合、ビルドは Multiple classes have been annotated with @ApplicationPath which is currently not supported というメッセージとともに失敗するでしょう。

複数の JAX-RS アプリケーションが定義されている場合、 quarkus.resteasy.ignoreApplicationClasses=true プロパティーを使用して、すべての明示的な Application クラスを無視することができます。これにより、すべてのリソースクラスが quarkus.resteasy.path で定義されたアプリケーションパス ( デフォルトは / ) を介して利用できるようになります。

JAX-RS アプリケーションのサポートの制限

RESTEasy エクステンションは、クラス javax.ws.rs.core.Application のメソッド getProperties() をサポートしていません。さらに、アノテーションされたリソース、プロバイダー、機能クラスをフィルタリングするために、 getClasses()getSingletons() のメソッドにのみ依存しています。組み込みのリソース、プロバイダー、機能クラスや、他のエクステンションで登録されたリソース、プロバイダー、機能クラスはフィルタリングされません。最後に、メソッド getSingletons() が返すオブジェクトは無視され、リソース、プロバイダー、機能クラスをフィルタリングするためにクラスのみが考慮されます。言い換えれば、メソッド getSingletons() は実際には getClasses() と同じように管理されます。

リソースのライフサイクル

Quarkusでは、すべてのJAX-RSリソースはCDI Bean として扱われます。 @Inject を介して他の Bean を注入したり、 @Transactional のようなバインディングを使用してインターセプターをバインドしたり、 @PostConstruct コールバックを定義したりすることが可能です。

リソースクラスでスコープアノテーションが宣言されていない場合は、スコープはデフォルトになります。デフォルトのスコープは quarkus.resteasy.singleton-resources プロパティーで制御できます。 true (デフォルト) に設定すると、( @javax.inject.Singleton で定義されているように) すべてのリクエストにサービスを提供するためのリソースクラスの 単一のインスタンス が作成されます。 false に設定すると、各リクエストごとにリソースクラスの 新しい インスタンス が作成されます。明示的な CDI スコープアノテーション ( @RequestScoped , @ApplicationScoped , など) は常にデフォルトの動作を上書きし、リソースインスタンスのライフサイクルを指定します。

ビルド時条件による JAX-RS クラスの包含および除外

Quarkusでは、CDI Beanの場合と同様に、ビルド時の条件に応じて、JAX-RSリソース、プロバイダー、および機能を直接包含または除外することができます。したがって、さまざまなJAX-RSクラスは、プロファイル条件( @io.quarkus.arc.profile.IfBuildProfile または @io.quarkus.arc.profile.UnlessBuildProfile )および/またはプロパティ条件( io.quarkus.arc.properties.IfBuildProperty または io.quarkus.arc.properties.UnlessBuildProperty )でアノテーションすることができ、構築時にどの条件でこれらのJAX-RSクラスが含まれるべきかをQuarkusに示すことができます。

次の例では、 Quarkus は、ビルドプロファイル app1 が有効になっている場合に限り、エンドポイント sayHello を含めます。

@IfBuildProfile("app1")
public class ResourceForApp1Only {

    @GET
    @Path("sayHello")
    public String sayHello() {
        return "hello";
     }
}

JAX-RS アプリケーションが検出され、メソッド getClasses() および、または getSingletons() がオーバーライドされている場合、 Quarkus はビルド時の条件を無視し、 JAX-RS アプリケーションで定義されているもののみを考慮することに注意してください。

まとめ

Quarkusを使用したJSON RESTサービスの作成は、実績のあるよく知られたテクノロジーに依存しているため、簡単に行えます。

いつものように、Quarkusは、アプリケーションをネイティブ実行可能ファイルとして実行する際に、水面下の作業をさらに簡略化しています。

覚えておくべきことは一つだけあります。 Response を使用していて、Quarkus がシリアライズされているBeanを特定できない場合は、 @RegisterForReflection を使ってアノテーションを付ける必要があります。