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

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 \
    --extension='resteasy-jackson' \
    --no-code
cd rest-json-quickstart

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

Quarkus CLIのインストール方法や使用方法については、<a href="cli-tooling.html">Quarkus CLIガイド</a> を参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.16.4.Final:create \
    -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 \
    --extension='resteasy-jsonb' \
    --no-code
cd rest-json-quickstart

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

Quarkus CLIのインストール方法や使用方法については、<a href="cli-tooling.html">Quarkus CLIガイド</a> を参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.16.4.Final:create \
    -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 は、 SerializationFeature.WRITE_DATES_AS_TIMESTAMPS 機能を無効化することで日付と時刻を ISO-8601 でフォーマットするように設定されています。

application.propertiesquarkus.jackson.write-dates-as-timestamps=true を設定すると、Jackson のデフォルトの動作を復元することができます。単一のフィールドのフォーマットを変更したい場合は、@JsonFormat アノテーションを使用することができます。

また、 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());
    }
}

より高度なオプションとしては、 Dependent スコープ付きの javax.json.bind.JsonbConfig の Bean を直接提供するか、極端な場合には Singleton スコープ付きの javax.json.bind.Jsonb のタイプの 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. Table Contect オブジェクト
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 は、 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;
    }
}

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

このメソッドは Legume のリストではなく Response を返ます。

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 は、非同期的に発行される可能性のある複数の項目がある場合に使用します。

Uni<Response> のように、 UniResponse を使用して、非同期 HTTP レスポンスを返すことができます。

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 というエクステンションを提供しています。

このエクステンションは RESTEasy のデフォルトの動作とは若干異なり、リクエストで何も指定されていない場合のデフォルトの文字セットは US-ASCII ではなく UTF-8 となります。

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

ビルド時に固定される設定プロパティ - その他の設定プロパティはランタイムでオーバーライド可能です。

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

Charset

UTF-8

The default content-type.

Environment variable: QUARKUS_RESTEASY_MULTIPART_INPUT_PART_DEFAULT_CONTENT_TYPE

string

text/plain

サーブレットとの互換性

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

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

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 に設定すると、各リクエストごとに、リソースクラスの 新しい インスタンスが作成されます。 @RequestScoped, @ApplicationScoped などの明示的な CDI スコープアノテーションは、常にデフォルトの動作を上書きし、リソースインスタンスのライフサイクルを指定することができます。

ビルド時条件による 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 を使ってアノテーションを付ける必要があることです。