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

Usando o Cliente REST

This guide explains how to use the REST Client in order to interact with REST APIs. REST Client is the REST Client implementation compatible with Quarkus REST (formerly RESTEasy Reactive).

If your application uses a client and exposes REST endpoints, please use Quarkus REST for the server part.

Pré-requisitos

Para concluir este guia, você precisa:

  • Cerca de 15 minutos

  • Um IDE

  • JDK 17+ installed with JAVA_HOME configured appropriately

  • Apache Maven 3.9.9

  • Opcionalmente, o Quarkus CLI se você quiser usá-lo

  • Opcionalmente, Mandrel ou GraalVM instalado e configurado apropriadamente se você quiser criar um executável nativo (ou Docker se você usar uma compilação de contêiner nativo)

Solução

Recomendamos que siga as instruções nas seções seguintes e crie a aplicação passo a passo. No entanto, você pode ir diretamente para o exemplo completo.

Clone o repositório Git: git clone https://github.com/quarkusio/quarkus-quickstarts.git, ou baixe um arquivo.

The solution is located in the rest-client-quickstart directory.

Criar o projeto Maven

Primeiro, precisamos de um novo projeto. Crie um novo projeto com o seguinte comando:

CLI
quarkus create app org.acme:rest-client-quickstart \
    --extension='rest-jackson,rest-client-jackson' \
    --no-code
cd rest-client-quickstart

Para criar um projeto Gradle, adicione a opção --gradle ou --gradle-kotlin-dsl.

Para obter mais informações sobre como instalar e usar a CLI do Quarkus, consulte o guia Quarkus CLI.

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.17.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=rest-client-quickstart \
    -Dextensions='rest-jackson,rest-client-jackson' \
    -DnoCode
cd rest-client-quickstart

Para criar um projeto Gradle, adicione a opção '-DbuildTool=gradle' ou '-DbuildTool=gradle-kotlin-dsl'.

Para usuários do Windows:

  • Se estiver usando cmd, (não use barra invertida '\' e coloque tudo na mesma linha)

  • Se estiver usando o Powershell, envolva os parâmetros '-D' entre aspas duplas, por exemplo, '"-DprojectArtifactId=rest-client-quickstart"'

Este comando gera o projeto Maven com um endpoint REST e com importações:

  • the rest-jackson extension for the REST server support. Use rest instead if you do not wish to use Jackson;

  • the rest-client-jackson extension for the REST client support. Use rest-client instead if you do not wish to use Jackson

If you already have your Quarkus project configured, you can add the rest-client-jackson extension to your project by running the following command in your project base directory:

CLI
quarkus extension add rest-client-jackson
Maven
./mvnw quarkus:add-extension -Dextensions='rest-client-jackson'
Gradle
./gradlew addExtension --extensions='rest-client-jackson'

Isto irá adicionar o seguinte trecho no seu arquivo de build:

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

Configurando o modelo

Neste guia, demonstraremos como consumir parte da API REST fornecida pelo serviço stage.code.quarkus.io . Nosso primeiro passo é configurar o modelo que usaremos, na forma de um POJO Extension .

Crie um arquivo src/main/java/org/acme/rest/client/Extension.java e defina o seguinte conteúdo:

package org.acme.rest.client;

import java.util.List;

public class Extension {

    public String id;
    public String name;
    public String shortName;
    public List<String> keywords;

}

O modelo acima é apenas um subconjunto dos campos fornecidos pelo serviço, mas é suficiente para os objetivos deste guia.

Crie a interface

Using the REST Client is as simple as creating an interface using the proper Jakarta REST and MicroProfile annotations. In our case the interface should be created at src/main/java/org/acme/rest/client/ExtensionsService.java and have the following content:

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import java.util.Set;

@Path("/extensions")
@RegisterRestClient
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);
}

O método getById dá ao nosso código a capacidade de obter uma extensão por id a partir da API do Code Quarkus. O cliente tratará de toda a ligação em rede e da organização, deixando o nosso código livre desses pormenores técnicos.

O objetivo das anotações no código acima é o seguinte:

  • @RegisterRestClient permite que o Quarkus saiba que essa interface deve estar disponível para injeção de CDI como um Cliente REST

  • @Path, @GET e @QueryParam são as anotações Jakarta REST padrão utilizadas para definir o modo de acesso ao serviço

When the quarkus-rest-client-jackson extension is installed, Quarkus will use the application/json media type by default for most return values, unless the media type is explicitly set via @Produces or @Consumes annotations.

Se você não conta com JSON padrão, é altamente recomendável anotar seus endpoints com as anotações @Produces e @Consumes para definir com precisão os tipos de conteúdo esperados. Isso permitirá reduzir o número de provedores Jakarta REST (que podem ser vistos como conversores) incluídos no executável nativo.

The getById method above is a blocking call. It should not be invoked on the event loop. The Suporte Assíncrono section describes how to make non-blocking calls.

Parâmetros de Consulta

A maneira mais fácil de especificar um parâmetro de consulta é anotar um parâmetro de método do cliente com @QueryParam ou @RestQuery . O @RestQuery é equivalente ao @QueryParam , mas com nome opcional. Além disso, ele também pode ser usado para passar parâmetros de consulta como Map , o que é conveniente se os parâmetros não forem conhecidos antecipadamente.

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.reactive.RestQuery;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MultivaluedMap;
import java.util.Map;
import java.util.Set;

@Path("/extensions")
@RegisterRestClient(configKey = "extensions-api")
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);

    @GET
    Set<Extension> getByName(@RestQuery String name); (1)

    @GET
    Set<Extension> getByFilter(@RestQuery Map<String, String> filter); (2)

    @GET
    Set<Extension> getByFilters(@RestQuery MultivaluedMap<String, String> filters); (3)

}
1 A consulta da requisição incluirá um parâmetro com a chave name
2 Cada entrada Map representa exatamente um parâmetro de consulta
3 MultivaluedMap permite enviar valores de vetor

Usando @ClientQueryParam

Outra forma de adicionar parâmetros de consulta a uma requisição é usar @io.quarkus.rest.client.reactive.ClientQueryParam na interface do cliente REST ou em um método específico da interface. A anotação pode especificar o nome do parâmetro de consulta, enquanto o valor pode ser uma constante, uma propriedade de configuração ou pode ser determinado pela chamada de um método.

O exemplo a seguir mostra as várias utilizações possíveis:

@ClientQueryParam(name = "my-param", value = "${my.property-value}") (1)
public interface Client {
    @GET
    String getWithParam();

    @GET
    @ClientQueryParam(name = "some-other-param", value = "other") (2)
    String getWithOtherParam();

    @GET
    @ClientQueryParam(name = "param-from-method", value = "{with-param}") (3)
    String getFromMethod();

    default String withParam(String name) {
        if ("param-from-method".equals(name)) {
            return "test";
        }
        throw new IllegalArgumentException();
    }
}
1 Ao colocar @ClientQueryParam na interface, garantimos que my-param será adicionado a todas as requisições do cliente. Como usamos a sintaxe ${…​}, o valor real do parâmetro será obtido usando a propriedade de configuração my.property-value .
2 Quando getWithOtherParam é chamado, além do parâmetro de consulta my-param, some-other-param com o valor de other também será adicionado.
3 quando getFromMethod é chamado, além do parâmetro de consulta my-param, param-from-method com o valor de test (porque é isso que o método withParam devolve quando invocado com param-from-method) também será adicionado.

Observe que, se um método de interface contiver um argumento anotado com @QueryParam , esse argumento terá prioridade sobre qualquer coisa especificada em qualquer anotação @ClientQueryParam .

More information about this annotation can be found on the javadoc of @ClientQueryParam.

Parâmetros do Formulário

Os parâmetros do formulário podem ser especificados utilizando as anotações @RestForm (ou @FormParam):

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.reactive.RestForm;

import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.core.MultivaluedMap;
import java.util.Map;
import java.util.Set;

@Path("/extensions")
@RegisterRestClient(configKey = "extensions-api")
public interface ExtensionsService {

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    Set<Extension> postId(@FormParam("id") String id);

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    Set<Extension> postName(@RestForm String name);

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    Set<Extension> postFilter(@RestForm Map<String, String> filter);

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    Set<Extension> postFilters(@RestForm MultivaluedMap<String, String> filters);

}

Usando @ClientFormParam

Os parâmetros do formulário também podem ser especificados utilizando @ClientFormParam, semelhante a @ClientQueryParam:

@ClientFormParam(name = "my-param", value = "${my.property-value}")
public interface Client {
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    String postWithParam();

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @ClientFormParam(name = "some-other-param", value = "other")
    String postWithOtherParam();

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @ClientFormParam(name = "param-from-method", value = "{with-param}")
    String postFromMethod();

    default String withParam(String name) {
        if ("param-from-method".equals(name)) {
            return "test";
        }
        throw new IllegalArgumentException();
    }
}

More information about this annotation can be found on the javadoc of @ClientFormParam.

Parâmetros do Caminho

Se a requisição GET exigir parâmetros de caminho, você poderá utilizar a anotação @PathParam("parameter-name") em vez de (ou além de) @QueryParam . Os parâmetros de caminho e de consulta podem ser combinados, conforme necessário, como ilustrado no exemplo abaixo.

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.QueryParam;
import java.util.Set;

@Path("/extensions")
@RegisterRestClient
public interface ExtensionsService {

    @GET
    @Path("/stream/{stream}")
    Set<Extension> getByStream(@PathParam("stream") String stream, @QueryParam("id") String id);
}

Dynamic base URLs

The REST client allows for a per invocation override of the base URL using the io.quarkus.rest.client.reactive.Url annotation.

Here is a simple example:

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.QueryParam;
import java.util.Set;

import io.quarkus.rest.client.reactive.Url;

@Path("/extensions")
@RegisterRestClient
public interface ExtensionsService {

    @GET
    @Path("/stream/{stream}")
    Set<Extension> getByStream(@Url String url, @PathParam("stream") String stream, @QueryParam("id") String id);
}

When the url parameter is non-null, it will override the base URL that is configured for the client (the default base URL configuration is still mandatory).

Sending large payloads

The REST Client is capable of sending arbitrarily large HTTP bodies without buffering the contents in memory, if one of the following types is used:

  • InputStream

  • Multi<io.vertx.mutiny.core.buffer.Buffer>

Furthermore, the client can also send arbitrarily large files if one of the following types is used:

  • File

  • Path

Getting other response properties

Using RestResponse

If you need to get more properties of the HTTP response than just the body, such as the status code or headers, you can make your method return org.jboss.resteasy.reactive.RestResponse from a method. An example of this could look like:

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.jboss.resteasy.reactive.RestQuery;
import org.jboss.resteasy.reactive.RestResponse;

import java.util.Set;

@Path("/extensions")
@RegisterRestClient
public interface ExtensionsService {

    @GET
    RestResponse<Set<Extension>> getByIdResponseProperties(@RestQuery String id);
}
You can also use the Jakarta REST type Response but it is not strongly typed to your entity.

Crie o recurso Jakarta REST

Crie o arquivo src/main/java/org/acme/rest/client/ExtensionsResource.java com o seguinte conteúdo:

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import java.util.Set;

@Path("/extension")
public class ExtensionsResource {

    @RestClient (1)
    ExtensionsService extensionsService;


    @GET
    @Path("/id/{id}")
    public Set<Extension> id(String id) {
        return extensionsService.getById(id);
    }

    @GET
    @Path("/properties")
    public RestResponse<Set<Extension>> responseProperties(@RestQuery String id) {
        RestResponse<Set<Extension>> clientResponse = extensionsService.getByIdResponseProperties(id); (2)
        String contentType = clientResponse.getHeaderString("Content-Type");
        int status = clientResponse.getStatus();
        String setCookie = clientResponse.getHeaderString("Set-Cookie");
        Date lastModified = clientResponse.getLastModified();

        Log.infof("content-Type: %s status: %s Last-Modified: %s Set-Cookie: %s", contentType, status, lastModified,
                setCookie);

        return RestResponse.fromResponse(clientResponse);
    }
}

Há duas partes interessantes nesta listagem:

1 o stub do cliente é injetado com a anotação @RestClient em vez da habitual anotação CDI @Inject
2 org.jboss.resteasy.reactive.RestResponse used as effective way of getting response properties via RestResponse directly from RestClient, as described in Using RestResponse

Crie a configuração

Para determinar o URL de base para o qual as chamadas REST serão feitas, o Cliente REST usa a configuração de application.properties. O nome da propriedade precisa seguir uma determinada convenção que é melhor exibida no código a seguir:

# Your configuration properties
quarkus.rest-client."org.acme.rest.client.ExtensionsService".url=https://stage.code.quarkus.io/api # (1)
1 Having this configuration means that all requests performed using org.acme.rest.client.ExtensionsService will use https://stage.code.quarkus.io/api as the base URL. Using the configuration above, calling the getById method of ExtensionsService with a value of io.quarkus:quarkus-rest-client would result in an HTTP GET request being made to https://stage.code.quarkus.io/api/extensions?id=io.quarkus:quarkus-rest-client.

Note que org.acme.rest.client.ExtensionsService deve corresponder ao nome totalmente qualificado da interface ExtensionsService que criamos na seção anterior.

Para facilitar a configuração, você pode utilizar a propriedade configKey de @RegisterRestClient que permite utilizar uma raiz de configuração diferente do nome totalmente qualificado da sua interface.

@RegisterRestClient(configKey="extensions-api")
public interface ExtensionsService {
    [...]
}
# Your configuration properties
quarkus.rest-client.extensions-api.url=https://stage.code.quarkus.io/api
quarkus.rest-client.extensions-api.scope=jakarta.inject.Singleton

Setting the base URL of the client is mandatory, however the REST Client supports per-invocation overrides of the base URL using the @io.quarkus.rest.client.reactive.Url annotation.

Desabilitando a Verificação do Nome do Host

Para desabilitar a verificação do nome do host SSL para um cliente REST específico, adicione a seguinte propriedade à sua configuração:

quarkus.rest-client.extensions-api.verify-host=false

Esta definição não deve ser utilizada em produção, uma vez que irá desativar a verificação do nome do host SSL.

Suporte HTTP/2

O HTTP/2 está desabilitado por padrão no Cliente REST. Se pretende habilitar, pode definir:

// for all REST Clients:
quarkus.rest-client.http2=true
// or for a single REST Client:
quarkus.rest-client.extensions-api.http2=true

Alternativamente, você pode habilitar a extensão TLS de Negociação de Protocolo de Camada de Aplicação (alpn) e o cliente irá determinar qual versão HTTP utilizar, dentre as que são compatíveis com o servidor. Por padrão, ele tentará usar o HTTP/2 primeiro e, se não estiver habilitado, usará o HTTP/1.1. Se você quiser habilitá-lo, você pode definir:

quarkus.rest-client.alpn=true
// or for a single REST Client:
quarkus.rest-client.extensions-api.alpn=true

Criação programática de clientes com o QuarkusRestClientBuilder

Em vez de anotar o cliente com @RegisterRestClient e injetar um cliente com @RestClient, você também pode criar um cliente REST de forma programática. Você faz isso com o QuarkusRestClientBuilder .

Com esta abordagem, a interface do cliente poderia ter o seguinte aspecto:

package org.acme.rest.client;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import java.util.Set;

@Path("/extensions")
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);
}

E o serviço é o seguinte:

package org.acme.rest.client;

import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import java.net.URI;
import java.util.Set;

@Path("/extension")
public class ExtensionsResource {

    private final ExtensionsService extensionsService;

    public ExtensionsResource() {
        extensionsService = QuarkusRestClientBuilder.newBuilder()
            .baseUri(URI.create("https://stage.code.quarkus.io/api"))
            .build(ExtensionsService.class);
    }

    @GET
    @Path("/id/{id}")
    public Set<Extension> id(String id) {
        return extensionsService.getById(id);
    }
}

A interface QuarkusRestClientBuilder é uma API específica do Quarkus para criar programaticamente clientes com opções de configuração adicionais. Caso contrário, você também pode utilizar a interface RestClientBuilder da API Microprofile:

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.RestClientBuilder;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import java.net.URI;
import java.util.Set;

@Path("/extension")
public class ExtensionsResource {

    private final ExtensionsService extensionsService;

    public ExtensionsResource() {
        extensionsService = RestClientBuilder.newBuilder()
            .baseUri(URI.create("https://stage.code.quarkus.io/api"))
            .build(ExtensionsService.class);
    }

    // ...
}

Usar Opções HTTP Personalizadas

The REST Client internally uses the Vert.x HTTP Client to make the network connections. The REST Client extensions allows configuring some settings via properties, for example:

  • quarkus.rest-client.client-prefix.connect-timeout para configurar o tempo limite de conexão em milissegundos.

  • quarkus.rest-client.client-prefix.max-redirects para limitar o número de redirecionamentos.

No entanto, existem muitas outras opções no Cliente HTTP Vert.x para configurar as conexões. Veja todas as opções na API de Opções do Cliente HTTP Vert.x neste link.

To fully customize the Vert.x HTTP Client instance that the REST Client is internally using, you can provide your custom HTTP Client Options instance via CDI or when programmatically creating your client.

Vejamos um exemplo de como fornecer as Opções de Cliente HTTP através de CDI:

package org.acme.rest.client;

import jakarta.enterprise.inject.Produces;
import jakarta.ws.rs.ext.ContextResolver;

import io.vertx.core.http.HttpClientOptions;
import io.quarkus.arc.Unremovable;

@Provider
public class CustomHttpClientOptions implements ContextResolver<HttpClientOptions> {

    @Override
    public HttpClientOptions getContext(Class<?> aClass) {
        HttpClientOptions options = new HttpClientOptions();
        // ...
        return options;
    }
}

Agora, todos os Clientes REST usarão suas Opções de Cliente HTTP personalizadas.

Outra abordagem é fornecer as opções do Cliente HTTP personalizadas ao criar o cliente programaticamente:

package org.acme.rest.client;

import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import java.net.URI;
import java.util.Set;

import io.vertx.core.http.HttpClientOptions;

@Path("/extension")
public class ExtensionsResource {

    private final ExtensionsService extensionsService;

    public ExtensionsResource() {
        HttpClientOptions options = new HttpClientOptions();
        // ...

        extensionsService = QuarkusRestClientBuilder.newBuilder()
            .baseUri(URI.create("https://stage.code.quarkus.io/api"))
            .httpClientOptions(options) (1)
            .build(ExtensionsService.class);
    }

    // ...
}
1 o cliente utilizará as opções de Cliente HTTP registradas em vez das opções de Cliente HTTP fornecidas via CDI, se existirem.

Redirecionamento

Um servidor HTTP pode redirecionar uma resposta para outra localização, enviando uma resposta com um código de estado que começa por "3" e um cabeçalho HTTP "Location" que contém o URL para onde deve ser redirecionado. Quando o Cliente REST recebe uma resposta de redirecionamento de um servidor HTTP, não efetua automaticamente outra requisição para a nova localização. Podemos ativar o redirecionamento automático no Cliente REST adicionando a propriedade "follow-redirects":

  • quarkus.rest-client.follow-redirects para ativar o redirecionamento para todos os clientes REST.

  • quarkus.rest-client.<client-prefix>.follow-redirects para ativar o redirecionamento para um cliente REST específico.

Se esta propriedade for verdadeira, então o Cliente REST efetuará uma nova requisição quando receber uma resposta de redirecionamento do servidor HTTP.

Além disso, podemos limitar o número de redirecionamentos utilizando a propriedade "max-redirects".

Uma nota importante é que, de acordo com as especificações RFC2616, por padrão o redirecionamento só ocorrerá para os métodos GET ou HEAD. No entanto, no Cliente REST, você pode fornecer o seu manipulador de redirecionamento personalizado para permitir o redirecionamento nos métodos POST ou PUT, ou para seguir uma lógica mais complexa, utilizando a anotação @ClientRedirectHandler, CDI ou programaticamente ao criar o seu cliente.

Vejamos um exemplo sobre como registrar o seu próprio manipulador de redirecionamento personalizado utilizando a anotação @ClientRedirectHandler:

import jakarta.ws.rs.core.Response;

import io.quarkus.rest.client.reactive.ClientRedirectHandler;

@RegisterRestClient(configKey="extensions-api")
public interface ExtensionsService {
    @ClientRedirectHandler
    static URI alwaysRedirect(Response response) {
        if (Response.Status.Family.familyOf(response.getStatus()) == Response.Status.Family.REDIRECTION) {
            return response.getLocation();
        }

        return null;
    }
}

O manipulador de redirecionamento "alwaysRedirect" só será utilizado pelo Cliente REST especificado que, neste exemplo, é o cliente "ExtensionsService".

Alternativamente, você também pode fornecer um manipulador de redirecionamento personalizado para todos os seus Clientes REST através de CDI:

import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ContextResolver;
import jakarta.ws.rs.ext.Provider;

import org.jboss.resteasy.reactive.client.handlers.RedirectHandler;

@Provider
public class AlwaysRedirectHandler implements ContextResolver<RedirectHandler> {

    @Override
    public RedirectHandler getContext(Class<?> aClass) {
        return response -> {
            if (Response.Status.Family.familyOf(response.getStatus()) == Response.Status.Family.REDIRECTION) {
                return response.getLocation();
            }
            // no redirect
            return null;
        };
    }
}

Agora, todos os Clientes REST usarão seu manipulador de redirecionamento personalizado.

Outra abordagem consiste em fornecê-lo programaticamente na criação do cliente:

@Path("/extension")
public class ExtensionsResource {

    private final ExtensionsService extensionsService;

    public ExtensionsResource() {
        extensionsService = QuarkusRestClientBuilder.newBuilder()
            .baseUri(URI.create("https://stage.code.quarkus.io/api"))
            .register(AlwaysRedirectHandler.class) (1)
            .build(ExtensionsService.class);
    }

    // ...
}
1 o cliente utilizará o manipulador de redirecionamento registrado em vez do manipulador de redirecionamento fornecido através do CDI, se existir.

Atualize o teste

Em seguida, precisamos atualizar o teste funcional para refletir as alterações feitas no endpoint. Edite o arquivo src/test/java/org/acme/rest/client/ExtensionsResourceTest.java e altere o conteúdo do teste para:

package org.acme.rest.client;

import io.quarkus.test.junit.QuarkusTest;

import org.junit.jupiter.api.Test;

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

@QuarkusTest
public class ExtensionsResourceTest {

    @Test
    public void testExtensionsIdEndpoint() {
        given()
            .when().get("/extension/id/io.quarkus:quarkus-rest-client")
            .then()
            .statusCode(200)
            .body("$.size()", is(1),
                "[0].id", is("io.quarkus:quarkus-rest-client"),
                "[0].name", is("REST Client"),
                "[0].keywords.size()", greaterThan(1),
                "[0].keywords", hasItem("rest-client"));
    }
}

O código acima utiliza as capacidades json-path do REST Assured.

Suporte Assíncrono

To get the full power of the reactive nature of the client, you can use the non-blocking flavor of REST Client extension, which comes with support for CompletionStage and Uni. Let’s see it in action by adding a getByIdAsync method in our ExtensionsService REST interface. The code should look like:

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import java.util.Set;
import java.util.concurrent.CompletionStage;

@Path("/extensions")
@RegisterRestClient(configKey = "extensions-api")
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);

    @GET
    CompletionStage<Set<Extension>> getByIdAsync(@QueryParam("id") String id);
}

Abra o arquivo src/main/java/org/acme/rest/client/ExtensionsResource.java e atualize-o com o seguinte conteúdo:

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.inject.RestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import java.util.Set;
import java.util.concurrent.CompletionStage;

@Path("/extension")
public class ExtensionsResource {

    @RestClient
    ExtensionsService extensionsService;


    @GET
    @Path("/id/{id}")
    public Set<Extension> id(String id) {
        return extensionsService.getById(id);
    }

    @GET
    @Path("/id-async/{id}")
    public CompletionStage<Set<Extension>> idAsync(String id) {
        return extensionsService.getByIdAsync(id);
    }
}

Please note that since the invocation is now non-blocking, the idAsync method will be invoked on the event loop, i.e. will not get offloaded to a worker pool thread and thus reducing hardware resource utilization. See Quarkus REST execution model for more details.

Para testar métodos assíncronos, adicione o método de teste abaixo em ExtensionsResourceTest:

@Test
public void testExtensionIdAsyncEndpoint() {
    given()
        .when().get("/extension/id-async/io.quarkus:quarkus-rest-client")
        .then()
        .statusCode(200)
        .body("$.size()", is(1),
            "[0].id", is("io.quarkus:quarkus-rest-client"),
            "[0].name", is("REST Client"),
            "[0].keywords.size()", greaterThan(1),
            "[0].keywords", hasItem("rest-client"));
}

A versão Uni é muito semelhante:

package org.acme.rest.client;

import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import java.util.Set;

@Path("/extensions")
@RegisterRestClient(configKey = "extensions-api")
public interface ExtensionsService {

    // ...

    @GET
    Uni<Set<Extension>> getByIdAsUni(@QueryParam("id") String id);
}

O ExtensionsResource torna-se:

package org.acme.rest.client;

import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import java.util.Set;

@Path("/extension")
public class ExtensionsResource {

    @RestClient
    ExtensionsService extensionsService;


    // ...

    @GET
    @Path("/id-uni/{id}")
    public Uni<Set<Extension>> idUni(String id) {
        return extensionsService.getByIdAsUni(id);
    }
}
Mutiny

O código anterior usa tipos reativos do Mutiny. Se você não estiver familiarizado com o Mutiny, consulte Mutiny - uma biblioteca de programação reativa intuitiva .

Ao retornar um Uni , cada assinatura invoca o serviço remoto. Isso significa que você pode reenviar a requisição assinando novamente o Uni , ou usar um retry da seguinte forma:

@RestClient ExtensionsService extensionsService;

// ...

extensionsService.getByIdAsUni(id)
    .onFailure().retry().atMost(10);

Se você usar um CompletionStage , precisará chamar o método do serviço para tentar novamente. Essa diferença vem do aspecto preguiçoso do Mutiny e de seu protocolo de assinatura. Mais detalhes sobre isso podem ser encontrados na documentação do Mutiny .

Suporte a Eventos Enviados pelo Servidor (SSE)

O consumo de eventos SSE é possível simplesmente declarando o tipo de resultado como um io.smallrye.mutiny.Multi .

O exemplo mais simples é:

package org.acme.rest.client;

import io.smallrye.mutiny.Multi;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@Path("/sse")
@RegisterRestClient(configKey = "some-api")
public interface SseClient {
     @GET
     @Produces(MediaType.SERVER_SENT_EVENTS)
     Multi<String> get();
}

Toda a E/S envolvida no streaming dos resultados do SSE é feita de forma não blocante.

Os resultados não se limitam a strings - por exemplo, quando o servidor retorna um payload JSON para cada evento, o Quarkus a desserializa automaticamente para o tipo genérico usado no Multi .

Os usuários também podem acessar todo o evento SSE usando o tipo org.jboss.resteasy.reactive.client.SseEvent .

Um exemplo simples em que os payloads do evento são valores Long é o seguinte:

package org.acme.rest.client;

import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.reactive.client.SseEvent;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;

@Path("/sse")
@RegisterRestClient(configKey = "some-api")
public interface SseClient {
     @GET
     @Produces(MediaType.SERVER_SENT_EVENTS)
     Multi<SseEvent<Long>> get();
}

Filtrando eventos

Ocasionalmente, o fluxo de eventos SSE pode conter alguns eventos que não devem ser retornados pelo cliente - um exemplo disso é fazer com que o servidor envie eventos de batimento cardíaco para manter aberta a conexão TCP subjacente. O Cliente REST oferece suporte à filtragem desses eventos, fornecendo o @org.jboss.resteasy.reactive.client.SseEventFilter .

Aqui está um exemplo de filtragem de eventos de batimento cardíaco:

package org.acme.rest.client;

import io.smallrye.mutiny.Uni;
import java.util.function.Predicate;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import org.jboss.resteasy.reactive.client.SseEvent;
import org.jboss.resteasy.reactive.client.SseEventFilter;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;

@Path("/sse")
@RegisterRestClient(configKey = "some-api")
public interface SseClient {

     @GET
     @Produces(MediaType.SERVER_SENT_EVENTS)
     @SseEventFilter(HeartbeatFilter.class)
     Multi<SseEvent<Long>> get();


     class HeartbeatFilter implements Predicate<SseEvent<String>> {

        @Override
        public boolean test(SseEvent<String> event) {
            return !"heartbeat".equals(event.id());
        }
     }
}

Suporte para cabeçalhos personalizados

Existem algumas formas de especificar cabeçalhos personalizados para as suas chamadas REST:

  • registrando um ClientHeadersFactory ou um ReactiveClientHeadersFactory com a anotação @RegisterClientHeaders

  • registrando programaticamente um ClientHeadersFactory ou um ReactiveClientHeadersFactory com o método QuarkusRestClientBuilder.clientHeadersFactory(factory)

  • especificando o valor do cabeçalho com @ClientHeaderParam

  • especificando o valor do cabeçalho por @HeaderParam

O código abaixo demonstra como utilizar cada uma destas técnicas:

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import java.util.Set;
import io.quarkus.rest.client.reactive.NotBody;

@Path("/extensions")
@RegisterRestClient
@RegisterClientHeaders(RequestUUIDHeaderFactory.class) (1)
@ClientHeaderParam(name = "my-header", value = "constant-header-value") (2)
@ClientHeaderParam(name = "computed-header", value = "{org.acme.rest.client.Util.computeHeader}") (3)
public interface ExtensionsService {

    @GET
    @ClientHeaderParam(name = "header-from-properties", value = "${header.value}") (4)
    @ClientHeaderParam(name = "header-from-method-param", value = "Bearer {token}") (5)
    Set<Extension> getById(@QueryParam("id") String id, @HeaderParam("jaxrs-style-header") String headerValue, @NotBody String token); (6)
}
1 Só pode haver um ClientHeadersFactory por classe. Com ela, é possível não só adicionar cabeçalhos personalizados, mas também transformar os existentes. Veja a classe RequestUUIDHeaderFactory abaixo para um exemplo da fábrica.
2 @ClientHeaderParam pode ser utilizado na interface do cliente e nos métodos. Pode especificar um valor de cabeçalho constante…​
3 …​ e um nome de um método que deve calcular o valor do cabeçalho. Pode ser um método estático ou um método padrão nesta interface. O método pode não receber nenhum parâmetro, um único parâmetro String ou um único parâmetro io.quarkus.rest.client.reactive.ComputedParamContext (que é muito útil para código que precisa calcular cabeçalhos com base em parâmetros de métodos e complementa naturalmente @io.quarkus.rest.client.reactive.NotBody).
4 …​ bem como um valor da configuração da sua aplicação
5 …​ ou mesmo qualquer mistura de texto literal, parâmetros de métodos (referenciados pelo nome), um valor de configuração (como mencionado anteriormente) e invocações de métodos (como mencionado anteriormente)
6 …​ ou como um argumento anotado do Jakarta REST @HeaderParam normal

Ao usar o Kotlin, se os métodos padrão forem aproveitados, o compilador do Kotlin precisará ser configurado para usar os recursos de interface padrão do Java. Veja isso para obter mais detalhes.

Um ClientHeadersFactory pode ter o seguinte aspecto:

package org.acme.rest.client;

import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import java.util.UUID;

@ApplicationScoped
public class RequestUUIDHeaderFactory implements ClientHeadersFactory {

    @Override
    public MultivaluedMap<String, String> update(MultivaluedMap<String, String> incomingHeaders, MultivaluedMap<String, String> clientOutgoingHeaders) {
        MultivaluedMap<String, String> result = new MultivaluedHashMap<>();
        result.add("X-request-uuid", UUID.randomUUID().toString());
        return result;
    }
}

Como você vê no exemplo acima, é possível tornar a implementação do ClientHeadersFactory um bean CDI anotando-o com uma anotação de definição de escopo, como @Singleton , @ApplicationScoped , etc.

Para especificar um valor para ${header.value}, basta colocar o seguinte no seu application.properties:

header.value=value of the header

Além disso, existe uma variante reativa de ClientHeadersFactory que permite realizar operações blocantes. Por exemplo:

package org.acme.rest.client;

import io.smallrye.mutiny.Uni;

import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import java.util.UUID;

@ApplicationScoped
public class GetTokenReactiveClientHeadersFactory extends ReactiveClientHeadersFactory {

    @Inject
    Service service;

    @Override
    public Uni<MultivaluedMap<String, String>> getHeaders(
            MultivaluedMap<String, String> incomingHeaders,
            MultivaluedMap<String, String> clientOutgoingHeaders) {
        return Uni.createFrom().item(() -> {
            MultivaluedHashMap<String, String> newHeaders = new MultivaluedHashMap<>();
            // perform blocking call
            newHeaders.add(HEADER_NAME, service.getToken());
            return newHeaders;
        });
    }
}

When using HTTP Basic Auth, the @io.quarkus.rest.client.reactive.ClientBasicAuth annotation provides a much simpler way of configuring the necessary Authorization header.

A very simple example is:

@ClientBasicAuth(username = "${service.username}", password = "${service.password}")
public interface SomeClient {

}

where service.username and service.password are configuration properties that must be set at runtime to the username and password that allow access to the service being called.

Fábrica de cabeçalhos padrão

A anotação @RegisterClientHeaders também pode ser usada sem nenhuma fábrica personalizada especificada. Nesse caso, será usada a fábrica DefaultClientHeadersFactoryImpl . Se você fizer uma chamada de cliente REST a partir de um recurso REST, essa fábrica propagará todos os cabeçalhos listados na propriedade de configuração org.eclipse.microprofile.rest.client.propagateHeaders da requisição do recurso para a requisição do cliente. Os nomes dos cabeçalhos individuais são separados por vírgulas.

@Path("/extensions")
@RegisterRestClient
@RegisterClientHeaders
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);

    @GET
    CompletionStage<Set<Extension>> getByIdAsync(@QueryParam("id") String id);
}
org.eclipse.microprofile.rest.client.propagateHeaders=Authorization,Proxy-Authorization

Personalização da requisição

The REST Client supports further customization of the final request to be sent to the server via filters. The filters must implement either the interface ClientRequestFilter or ResteasyReactiveClientRequestFilter.

Um exemplo simples de personalização da requisição seria adicionar um cabeçalho personalizado:

@Provider
public class TestClientRequestFilter implements ClientRequestFilter {

    @Override
    public void filter(ClientRequestContext requestContext) {
        requestContext.getHeaders().add("my_header", "value");
    }
}

Em seguida, pode registrar o seu filtro utilizando a anotação @RegisterProvider:

@Path("/extensions")
@RegisterProvider(TestClientRequestFilter.class)
public interface ExtensionsService {

    // ...
}

Ou programaticamente, utilizando o método .register():

QuarkusRestClientBuilder.newBuilder()
    .register(TestClientRequestFilter.class)
    .build(ExtensionsService.class)

Injetando a instância jakarta.ws.rs.ext.Providers em filtros

O jakarta.ws.rs.ext.Providers é útil quando precisamos procurar as instâncias do fornecedor do cliente atual.

Podemos obter a instância Providers nos nossos filtros a partir do contexto do requisição da seguinte forma:

@Provider
public class TestClientRequestFilter implements ClientRequestFilter {

    @Override
    public void filter(ClientRequestContext requestContext) {
        Providers providers = ((ResteasyReactiveClientRequestContext) requestContext).getProviders();
        // ...
    }
}

Alternativamente, pode implementar a interface ResteasyReactiveClientRequestFilter em vez da interface ClientRequestFilter, que fornecerá diretamente o contexto ResteasyReactiveClientRequestContext:

@Provider
public class TestClientRequestFilter implements ResteasyReactiveClientRequestFilter {

    @Override
    public void filter(ResteasyReactiveClientRequestFilter requestContext) {
        Providers providers = requestContext.getProviders();
        // ...
    }
}

Customizing the ObjectMapper in REST Client Jackson

The REST Client supports adding a custom ObjectMapper to be used only the Client using the annotation @ClientObjectMapper.

A simple example is to provide a custom ObjectMapper to the REST Client Jackson extension by doing:

@Path("/extensions")
@RegisterRestClient
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);

    @ClientObjectMapper (1)
    static ObjectMapper objectMapper(ObjectMapper defaultObjectMapper) { (2)
        return defaultObjectMapper.copy() (3)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .disable(DeserializationFeature.UNWRAP_ROOT_VALUE);
    }
}
1 O método deve ser anotado com @ClientObjectMapper.
2 Tem que ser um método estático. Além disso, o parâmetro defaultObjectMapper será resolvido através do CDI. Se não for encontrado, será lançada uma exceção em tempo de execução.
3 Neste exemplo, estamos criando uma cópia do mapeador de objetos padrão. Você NUNCA deve modificar o mapeador de objetos padrão, mas sim criar uma cópia.

Tratamento de exceções

A especificação do Cliente REST MicroProfile introduz o org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper, cujo objetivo é converter uma resposta HTTP numa exceção.

Um exemplo simples de implementação de tal ResponseExceptionMapper para o ExtensionsService discutido acima, poderia ser:

public class MyResponseExceptionMapper implements ResponseExceptionMapper<RuntimeException> {

    @Override
    public RuntimeException toThrowable(Response response) {
        if (response.getStatus() == 500) {
            throw new RuntimeException("The remote service responded with HTTP 500");
        }
        return null;
    }
}

ResponseExceptionMapper também define o método getPriority , que é usado para determinar a prioridade com que as implementações de ResponseExceptionMapper serão chamadas (as implementações com um valor menor para getPriority serão chamadas primeiro). Se toThrowable retornar uma exceção, essa exceção será lançada. Se null for retornado, a próxima implementação de ResponseExceptionMapper na cadeia será chamada (se houver alguma).

The class as written above, would not be automatically be used by any REST Client. To make it available to every REST Client of the application, the class needs to be annotated with @Provider (as long as quarkus.rest-client.provider-autodiscovery is not set to false). Alternatively, if the exception handling class should only apply to specific REST Client interfaces, you can either annotate the interfaces with @RegisterProvider(MyResponseExceptionMapper.class), or register it using configuration using the providers property of the proper quarkus.rest-client configuration group.

Usando @ClientExceptionMapper

Uma forma mais simples de converter códigos de resposta HTTP de 400 pra cima é utilizar a anotação @ClientExceptionMapper.

Para a interface de Cliente REST ExtensionsService definida acima, um exemplo de utilização de @ClientExceptionMapper seria:

@Path("/extensions")
@RegisterRestClient
public interface ExtensionsService {

    @GET
    Set<Extension> getById(@QueryParam("id") String id);

    @GET
    CompletionStage<Set<Extension>> getByIdAsync(@QueryParam("id") String id);

    @ClientExceptionMapper
    static RuntimeException toException(Response response) {
        if (response.getStatus() == 500) {
            return new RuntimeException("The remote service responded with HTTP 500");
        }
        return null;
    }
}

Naturalmente, este tratamento é efetuado por Cliente REST. @ClientExceptionMapper utiliza a prioridade predefinida se o atributo priority não estiver definido e aplicam-se as regras normais de invocação de todos os manipuladores sucessivamente.

Os métodos anotados com @ClientExceptionMapper também podem receber um parâmetro java.lang.reflect.Method, o que é útil se o código de mapeamento de exceções precisar conhecer o método do Cliente REST que foi invocado e causou a ativação do código de mapeamento de exceções.

Usando a anotação @Blocking em mapeadores de exceções

Em casos que justifiquem a utilização de InputStream como tipo de retorno do método do Cliente REST (por exemplo, quando é necessário ler grandes quantidades de dados):

@Path("/echo")
@RegisterRestClient
public interface EchoClient {

    @GET
    InputStream get();
}

Isso funcionará como esperado, mas se você tentar ler esse objeto InputStream em um mapeador de exceções personalizado, receberá uma exceção BlockingNotAllowedException. Isso ocorre porque as classes ResponseExceptionMapper são executadas no executor de thread do Loop de Eventos por padrão - o que não permite realizar operações de E/S.

Para tornar o seu mapeador de exceções blocante, pode anotar o mapeador de exceções com a anotação @Blocking:

@Provider
@Blocking (1)
public class MyResponseExceptionMapper implements ResponseExceptionMapper<RuntimeException> {

    @Override
    public RuntimeException toThrowable(Response response) {
        if (response.getStatus() == 500) {
            response.readEntity(String.class); (2)
            return new RuntimeException("The remote service responded with HTTP 500");
        }
        return null;
    }
}
1 Com a anotação @Blocking, o mapeador de exceções MyResponseExceptionMapper será executado no pool de threads de trabalho.
2 A leitura da entidade é agora permitida porque estamos executando o mapeador no pool de threads de trabalho.

Note que também pode utilizar a anotação @Blocking quando utilizar @ClientExceptionMapper:

@Path("/echo")
@RegisterRestClient
public interface EchoClient {

    @GET
    InputStream get();

    @ClientExceptionMapper
    @Blocking
    static RuntimeException toException(Response response) {
        if (response.getStatus() == 500) {
            response.readEntity(String.class);
            return new RuntimeException("The remote service responded with HTTP 500");
        }
        return null;
    }
}

Suporte a Formulários Multi-partes

Enviando Mensagens Multi-partes

REST Client allows sending data as multipart forms. This way you can for example send files efficiently.

Para enviar dados como um formulário multi-partes, você pode simplesmente utilizar as anotações normais @RestForm (ou @FormParam):

    @POST
    @Path("/binary")
    String sendMultipart(@RestForm File file, @RestForm String otherField);

Parameters specified as File, Path, byte[], Buffer or FileUpload are sent as files and default to the application/octet-stream MIME type. Other @RestForm parameter types default to the text/plain MIME type. You can override these defaults with the @PartType annotation.

Naturalmente, também é possível agrupar estes parâmetros numa classe que os contenha:

    public static class Parameters {
        @RestForm
        File file;

        @RestForm
        String otherField;
    }

    @POST
    @Path("/binary")
    String sendMultipart(Parameters parameters);

Any @RestForm parameter of the type File, Path, byte[], Buffer or FileUpload, as well as any annotated with @PartType automatically imply a @Consumes(MediaType.MULTIPART_FORM_DATA) on the method if there is no @Consumes present.

Se houver parâmetros @RestForm que não implicam em multi-parte, então @Consumes(MediaType.APPLICATION_FORM_URLENCODED) estará implícito.

There are a few modes in which the form data can be encoded. By default, REST Client uses RFC1738. You can override it by specifying the mode either on the client level, by setting io.quarkus.rest.client.multipart-post-encoder-mode RestBuilder property to the selected value of HttpPostRequestEncoder.EncoderMode or by specifying quarkus.rest-client.multipart-post-encoder-mode in your application.properties. Please note that the latter works only for clients created with the @RegisterRestClient annotation. All the available modes are described in the Netty documentation

Você também pode enviar multi-partes JSON especificando a anotação @PartType:

    public static class Person {
        public String firstName;
        public String lastName;
    }

    @POST
    @Path("/json")
    String sendMultipart(@RestForm @PartType(MediaType.APPLICATION_JSON) Person person);

Programmatically creating the Multipart form

In cases where the multipart content needs to be built up programmatically, the REST Client provides ClientMultipartForm which can be used in the REST Client like so:

public interface MultipartService {

  @POST
  @Path("/multipart")
  @Consumes(MediaType.MULTIPART_FORM_DATA)
  @Produces(MediaType.APPLICATION_JSON)
  Map<String, String> multipart(ClientMultipartForm dataParts);
}

More information about this class and supported methods can be found on the javadoc of ClientMultipartForm.

Converting a received multipart object into a client request

A good example of creating ClientMultipartForm is one where it is created from the server’s MultipartFormDataInput (which represents a multipart request received by Quarkus REST) - the purpose being to propagate the request downstream while allowing for arbitrary modifications:

public ClientMultipartForm buildClientMultipartForm(MultipartFormDataInput inputForm) (1)
    throws IOException {
  ClientMultipartForm multiPartForm = ClientMultipartForm.create(); (2)
  for (Entry<String, Collection<FormValue>> attribute : inputForm.getValues().entrySet()) {
    for (FormValue fv : attribute.getValue()) {
      if (fv.isFileItem()) {
        final FileItem fi = fv.getFileItem();
        String mediaType = Objects.toString(fv.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE),
            MediaType.APPLICATION_OCTET_STREAM);
        if (fi.isInMemory()) {
          multiPartForm.binaryFileUpload(attribute.getKey(), fv.getFileName(),
              Buffer.buffer(IOUtils.toByteArray(fi.getInputStream())), mediaType); (3)
        } else {
          multiPartForm.binaryFileUpload(attribute.getKey(), fv.getFileName(),
              fi.getFile().toString(), mediaType); (4)
        }
      } else {
        multiPartForm.attribute(attribute.getKey(), fv.getValue(), fv.getFileName()); (5)
      }
    }
  }
  return multiPartForm;
}
1 MultipartFormDataInput is a Quarkus REST (Server) type representing a received multipart request.
2 A ClientMultipartForm is created.
3 FileItem attribute is created for the request attribute that represented an in memory file attribute
4 FileItem attribute is created for the request attribute that represented a file attribute saved on the file system
5 Non-file attributes added directly to ClientMultipartForm if not FileItem.

In a similar fashion if the received server multipart request is known and looks something like:

public class Request { (1)

  @RestForm("files")
  @PartType(MediaType.APPLICATION_OCTET_STREAM)
  List<FileUpload> files;

  @RestForm("jsonPayload")
  @PartType(MediaType.TEXT_PLAIN)
  String jsonPayload;
}

the ClientMultipartForm can be created easily as follows:

public ClientMultipartForm buildClientMultipartForm(Request request) { (1)
  ClientMultipartForm multiPartForm = ClientMultipartForm.create();
  multiPartForm.attribute("jsonPayload", request.getJsonPayload(), "jsonPayload"); (2)
  request.getFiles().forEach(fu -> {
    multiPartForm.fileUpload(fu); (3)
  });
  return multiPartForm;
}
1 Request representing the request the server parts accepts
2 A jsonPayload attribute is added directly to ClientMultipartForm
3 A fileUpload is created from the request’s FileUpload

When sending multipart data that uses the same name, problems can arise if the client and server do not use the same multipart encoder mode. By default, the REST Client uses RFC1738, but depending on the situation, clients may need to be configured with HTML5 or RFC3986 mode.

This configuration can be achieved via the quarkus.rest-client.multipart-post-encoder-mode property.

Recebendo Mensagens Multi-partes

REST Client also supports receiving multipart messages. As with sending, to parse a multipart response, you need to create a class that describes the response data, e.g.

public class FormDto {
    @RestForm (1)
    @PartType(MediaType.APPLICATION_OCTET_STREAM)
    public File file;

    @FormParam("otherField") (2)
    @PartType(MediaType.TEXT_PLAIN)
    public String textProperty;
}
1 utiliza a anotação abreviada @RestForm para criar um campo como parte de um formulário multi-partes
2 a norma @FormParam também pode ser utilizada. Permite substituir o nome da parte multi-partes.

Em seguida, crie um método de interface que corresponda à chamada e faça-o devolver o FormDto:

    @GET
    @Produces(MediaType.MULTIPART_FORM_DATA)
    @Path("/get-file")
    FormDto data receiveMultipart();

Atualmente, o suporte de respostas multi-partes está sujeito às seguintes limitações:

  • os arquivos enviados em respostas multi-partes só podem ser analisados em File, Path e FileDownload

  • cada campo do tipo de resposta tem de ser anotado com @PartType - os campos sem esta anotação são ignorados

REST Client needs to know the classes used as multipart return types upfront. If you have an interface method that produces multipart/form-data, the return type will be discovered automatically. However, if you intend to use the ClientBuilder API to parse a response as multipart, you need to annotate your DTO class with @MultipartForm.

Os arquivos que você baixa não são removidos automaticamente e podem ocupar muito espaço no disco. Considere a remoção dos arquivos quando terminar de trabalhar com eles.

Utilização de multi-partes mistas / OData

Não é incomum que um aplicativo precise interagir com sistemas corporativos (como sistemas de CRM) usando um protocolo especial chamado OData . Esse protocolo usa essencialmente um Content-Type HTTP personalizado que precisa de algum código de cola para funcionar com o Cliente REST (a criação do corpo depende inteiramente da aplicação - o Cliente REST não pode fazer muito para ajudar).

Um exemplo é o seguinte:

@Path("/crm")
@RegisterRestClient
public interface CRMService {

    @POST
    @ClientHeaderParam(name = "Content-Type", value = "{calculateContentType}")  (1)
    String performBatch(@HeaderParam("Authorization") String accessToken, @NotBody String batchId, String body); (2)

    default String calculateContentType(ComputedParamContext context) {
        return "multipart/mixed;boundary=batch_" + context.methodParameters().get(1).value(); (3)
    }
}

O código utiliza os seguintes elementos:

1 @ClientHeaderParam(name = "Content-Type", value = "{calculateContentType}") que garante que o cabeçalho Content-Type é criado chamando o método padrão calculateContentType da interface.
2 O parâmetro acima mencionado precisa de ser anotado com @NotBody porque só é utilizado para ajudar na construção de cabeçalhos HTTP.
3 context.methodParameters().get(1).value() que permite que o método calculateContentType obtenha o parâmetro de método correto passado para o método do Cliente REST.

Tal como referido anteriormente, o parâmetro do corpo tem de ser corretamente elaborado pelo código da aplicação para estar em conformidade com os requisitos do serviço.

Recebendo mensagens comprimidas

REST Client also supports receiving compressed messages using GZIP. You can enable the HTTP compression support by adding the property quarkus.http.enable-compression=true. When this feature is enabled and a server returns a response that includes the header Content-Encoding: gzip, REST Client will automatically decode the content and proceed with the message handling.

Suporte de proxy

REST Client supports sending requests through a proxy. It honors the JVM settings for it but also allows to specify both:

  • definições globais de proxy de cliente, com quarkus.rest-client.proxy-address, quarkus.rest-client.proxy-user, quarkus.rest-client.proxy-password, quarkus.rest-client.non-proxy-hosts

  • definições de proxy por cliente, com quarkus.rest-client.<my-client>.proxy-address, etc. Estas são aplicadas apenas a clientes injetados com CDI, ou seja, os criados com @RegisterRestClient

Se proxy-address estiver definido no nível do cliente, o cliente utiliza as suas definições de proxy específicas. Nenhuma definição de proxy é propagada a partir da configuração global ou das propriedades da JVM.

Se proxy-address não estiver definido para o cliente, mas estiver definido no nível global, o cliente usará as configurações globais. Caso contrário, o cliente usará as configurações da JVM.

Um exemplo de configuração para definir o proxy:

# global proxy configuration is used for all clients
quarkus.rest-client.proxy-address=localhost:8182
quarkus.rest-client.proxy-user=<proxy user name>
quarkus.rest-client.proxy-password=<proxy password>
quarkus.rest-client.non-proxy-hosts=example.com

# per-client configuration overrides the global settings for a specific client
quarkus.rest-client.my-client.proxy-address=localhost:8183
quarkus.rest-client.my-client.proxy-user=<proxy user name>
quarkus.rest-client.my-client.proxy-password=<proxy password>
quarkus.rest-client.my-client.url=...
A especificação do Cliente REST MicroProfile não permite a definição de credenciais de proxy. Para especificar o usuário e a senha do proxy de forma programática, é necessário enviar o seu RestClientBuilder para RestClientBuilderImpl.

Local proxy for dev mode

When using the REST Client in dev mode, Quarkus has the ability to stand up a pass-through proxy which can be used as a target for Wireshark (or similar tools) in order to capture all the traffic originating from the REST Client (this really makes sense when the REST Client is used against HTTPS services)

To enable this feature, all that needs to be done is set the enable-local-proxy configuration option for the configKey corresponding to the client for which proxying is desired. For example:

quarkus.rest-client.my-client.enable-local-proxy=true

When a REST Client does not use a config key (for example when it is created programmatically via QuarkusRestClientBuilder) then the class name can be used instead. For example:

quarkus.rest-client."org.acme.SomeClient".enable-local-proxy=true

The port the proxy is listening can be found in startup logs. An example entry is:

Started HTTP proxy server on http://localhost:38227 for REST Client 'org.acme.SomeClient'

Empacote e execute a aplicação

Execute a aplicação com:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

Você deve ver um objeto JSON que contém algumas informações básicas sobre esta extensão.

Como de costume, a aplicação pode ser empacotada utilizando:

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

E executado com java -jar target/quarkus-app/quarkus-run.jar.

Também é possível gerar o executável nativo com:

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true

Registrando tráfego

REST Client can log the requests it sends and the responses it receives. To enable logging, add the quarkus.rest-client.logging.scope property to your application.properties and set it to:

  • request-response para registrar o conteúdo da requisição e da resposta, ou

  • all para permitir também o registro de baixo nível das bibliotecas subjacentes.

Como as mensagens HTTP podem ter corpos grandes, limitamos a quantidade de caracteres do corpo registrado. O limite padrão é 100, pode alterá-lo especificando quarkus.rest-client.logging.body-limit.

REST Client is logging the traffic with level DEBUG and does not alter logger properties. You may need to adjust your logger configuration to use this feature.

Um exemplo de configuração de registro:

quarkus.rest-client.logging.scope=request-response
quarkus.rest-client.logging.body-limit=50

quarkus.log.category."org.jboss.resteasy.reactive.client.logging".level=DEBUG

REST Client uses a default ClientLogger implementation, which can be swapped out for a custom implementation.

When setting up the client programmatically using the QuarkusRestClientBuilder, the ClientLogger is set via the clientLogger method.

For declarative clients using @RegisterRestClient, simply providing a CDI bean that implements ClientLogger is enough for that logger to be used by said clients.

Simulação do cliente para testes

Se você usar um cliente injetado com a anotação @RestClient, poderá facilmente simulá-lo para testes. Você pode fazer isso com @InjectMock do Mockito ou com QuarkusMock .

Esta seção mostra como substituir o seu cliente por uma simulação. Se pretender obter uma compreensão mais aprofundada de como funciona a simulação no Quarkus, consulte a publicação do blog sobre a simulação de beans CDI.

A simulação não funciona quando se utiliza @QuarkusIntegrationTest.

Vamos supor que você tem o seguinte cliente:

package io.quarkus.it.rest.client.main;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;


@Path("/")
@RegisterRestClient
public interface Client {
    @GET
    String get();
}

Simulando com InjectMock

A abordagem mais simples para simular um cliente para testes é usar Mockito e @InjectMock.

Primeiro, adicione a seguinte dependência à sua aplicação:

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

Depois, no seu teste, pode simplesmente utilizar @InjectMock para criar e injetar uma simulação:

package io.quarkus.it.rest.client.main;

import static org.mockito.Mockito.when;

import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class InjectMockTest {

    @InjectMock
    @RestClient
    Client mock;

    @BeforeEach
    public void setUp() {
        when(mock.get()).thenReturn("MockAnswer");
    }

    @Test
    void doTest() {
        // ...
    }
}

Simulando com o QuarkusMock

Se o Mockito não satisfizer as suas necessidades, você pode criar uma simulação programaticamente utilizando QuarkusMock, e.g.:

package io.quarkus.it.rest.client.main;

import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusMock;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class QuarkusMockTest {

    @BeforeEach
    public void setUp() {
        Client customMock = new Client() { (1)
            @Override
            public String get() {
                return "MockAnswer";
            }
        };
        QuarkusMock.installMockForType(customMock, Client.class, RestClient.LITERAL); (2)
    }
    @Test
    void doTest() {
        // ...
    }
}
1 aqui utilizamos uma implementação criada manualmente da interface do cliente para substituir a interface do cliente atual
2 note-se que RestClient.LITERAL tem de ser passado como último argumento do método installMockForType

Usando um Servidor HTTP Simulado para testes

Setting up a mock HTTP server, against which tests are run, is a common testing pattern. Examples of such servers are Wiremock and Hoverfly. In this section we’ll demonstrate how Wiremock can be leveraged for testing the ExtensionsService which was developed above.

First, Wiremock needs to be added as a test dependency. For a Maven project that would happen like so:

pom.xml
<dependency>
    <groupId>org.wiremock</groupId>
    <artifactId>wiremock</artifactId>
    <scope>test</scope>
    <version>${wiremock.version}</version> (1)
</dependency>
1 Use a proper Wiremock version. All available versions can be found here.
build.gradle
testImplementation("org.wiremock:wiremock:$wiremockVersion") (1)
1 Use a proper Wiremock version. All available versions can be found here.

In Quarkus tests when some service needs to be started before the Quarkus tests are ran, we utilize the @io.quarkus.test.common.QuarkusTestResource annotation to specify a io.quarkus.test.common.QuarkusTestResourceLifecycleManager which can start the service and supply configuration values that Quarkus will use.

For more details about @QuarkusTestResource refer to this part of the documentation.

Let’s create an implementation of QuarkusTestResourceLifecycleManager called WiremockExtensions like so:

package org.acme.rest.client;

import java.util.Map;

import com.github.tomakehurst.wiremock.WireMockServer;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

import static com.github.tomakehurst.wiremock.client.WireMock.*; (1)

public class WireMockExtensions implements QuarkusTestResourceLifecycleManager {  (2)

    private WireMockServer wireMockServer;

    @Override
    public Map<String, String> start() {
        wireMockServer = new WireMockServer();
        wireMockServer.start(); (3)

        wireMockServer.stubFor(get(urlEqualTo("/extensions?id=io.quarkus:quarkus-rest-client"))   (4)
                .willReturn(aResponse()
                        .withHeader("Content-Type", "application/json")
                        .withBody(
                            "[{" +
                            "\"id\": \"io.quarkus:quarkus-rest-client\"," +
                            "\"name\": \"REST Client\"" +
                            "}]"
                        )));

        wireMockServer.stubFor(get(urlMatching(".*")).atPriority(10).willReturn(aResponse().proxiedFrom("https://stage.code.quarkus.io/api")));   (5)

        return Map.of("quarkus.rest-client.\"org.acme.rest.client.ExtensionsService\".url", wireMockServer.baseUrl()); (6)
    }

    @Override
    public void stop() {
        if (null != wireMockServer) {
            wireMockServer.stop();  (7)
        }
    }
}
1 Statically importing the methods in the Wiremock package makes it easier to read the test.
2 The start method is invoked by Quarkus before any test is run and returns a Map of configuration properties that apply during the test execution.
3 Launch Wiremock.
4 Configure Wiremock to stub the calls to /extensions?id=io.quarkus:quarkus-rest-client by returning a specific canned response.
5 All HTTP calls that have not been stubbed are handled by calling the real service. This is done for demonstration purposes, as it is not something that would usually happen in a real test.
6 As the start method returns configuration that applies for tests, we set the rest-client property that controls the base URL which is used by the implementation of ExtensionsService to the base URL where Wiremock is listening for incoming requests.
7 When all tests have finished, shutdown Wiremock.

The ExtensionsResourceTest test class needs to be annotated like so:

@QuarkusTest
@QuarkusTestResource(WireMockExtensions.class)
public class ExtensionsResourceTest {

}

@QuarkusTestResource applies to all tests, not just ExtensionsResourceTest.

Limitações conhecidas

While the REST Client extension aims to be a drop-in replacement for the RESTEasy Client extension, there are some differences and limitations:

  • the default scope of the client for the new extension is @ApplicationScoped while the quarkus-resteasy-client defaults to @Dependent To change this behavior, set the quarkus.rest-client.scope property to the fully qualified scope name.

  • não é possível definir HostnameVerifier ou SSLContext

  • algumas coisas que não fazem sentido para implementações não blocantes, como a definição do ExecutorService, não funcionam

Referência de configuração

Propriedade de Configuração Fixa no Momento da Compilação - Todas as outras propriedades de configuração podem ser sobrepostas em tempo de execução.

Configuration property

Tipo

Padrão

By default, RESTEasy Reactive uses text/plain content type for String values and application/json for everything else.

MicroProfile Rest Client spec requires the implementations to always default to application/json. This build item disables the "smart" behavior of RESTEasy Reactive to comply to the spec

Environment variable: QUARKUS_REST_CLIENT_DISABLE_SMART_PRODUCES

Show more

boolean

false

Whether providers (filters, etc.) annotated with jakarta.ws.rs.ext.Provider should be automatically registered for all the clients in the application.

Environment variable: QUARKUS_REST_CLIENT_PROVIDER_AUTODISCOVERY

Show more

boolean

true

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Tipo

Padrão

If true, the extension will automatically remove the trailing slash in the paths if any. This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT_REMOVES_TRAILING_SLASH

Show more

boolean

true

Mode in which the form data are encoded. Possible values are HTML5, RFC1738 and RFC3986. The modes are described in the Netty documentation

By default, Rest Client Reactive uses RFC1738.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT_MULTIPART_POST_ENCODER_MODE

Show more

string

A string value in the form of : that specifies the HTTP proxy server hostname (or IP address) and port for requests of clients to use.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_PROXY_ADDRESS

Show more

string

Proxy username, equivalent to the http.proxy or https.proxy JVM settings.

Can be overwritten by client-specific settings.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT_PROXY_USER

Show more

string

Proxy password, equivalent to the http.proxyPassword or https.proxyPassword JVM settings.

Can be overwritten by client-specific settings.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT_PROXY_PASSWORD

Show more

string

Hosts to access without proxy, similar to the http.nonProxyHosts or https.nonProxyHosts JVM settings. Please note that unlike the JVM settings, this property is empty by default.

Can be overwritten by client-specific settings.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT_NON_PROXY_HOSTS

Show more

string

A timeout in milliseconds that REST clients should wait to connect to the remote endpoint.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_CONNECT_TIMEOUT

Show more

long

15000

A timeout in milliseconds that REST clients should wait for a response from the remote endpoint.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_READ_TIMEOUT

Show more

long

30000

If true, the REST clients will not provide additional contextual information (like REST client class and method names) when exception occurs during a client invocation.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT_DISABLE_CONTEXTUAL_ERROR_MESSAGES

Show more

boolean

false

Default configuration for the HTTP user-agent header to use in all REST clients.

Can be overwritten by client-specific settings.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT_USER_AGENT

Show more

string

The HTTP headers that should be applied to all requests of the rest client.

Environment variable: QUARKUS_REST_CLIENT_HEADERS__HEADER_NAME_

Show more

Map<String,String>

The class name of the host name verifier. The class must have a public no-argument constructor.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_HOSTNAME_VERIFIER

Show more

string

The time in ms for which a connection remains unused in the connection pool before being evicted and closed. A timeout of 0 means there is no timeout.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_CONNECTION_TTL

Show more

int

The size of the connection pool for this client.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_CONNECTION_POOL_SIZE

Show more

int

If set to false disables the keep alive completely.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_KEEP_ALIVE_ENABLED

Show more

boolean

true

The maximum number of redirection a request can follow.

Can be overwritten by client-specific settings.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT_MAX_REDIRECTS

Show more

int

A boolean value used to determine whether the client should follow HTTP redirect responses.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_FOLLOW_REDIRECTS

Show more

boolean

Map where keys are fully-qualified provider classnames to include in the client, and values are their integer priorities. The equivalent of the @RegisterProvider annotation.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_PROVIDERS

Show more

string

The CDI scope to use for injections of REST client instances. Value can be either a fully qualified class name of a CDI scope annotation (such as "jakarta.enterprise.context.ApplicationScoped") or its simple name (such as"ApplicationScoped").

Default scope for the rest-client extension is "Dependent" (which is the spec-compliant behavior).

Default scope for the rest-client-reactive extension is "ApplicationScoped".

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_SCOPE

Show more

string

An enumerated type string value with possible values of "MULTI_PAIRS" (default), "COMMA_SEPARATED", or "ARRAY_PAIRS" that specifies the format in which multiple values for the same query parameter is used.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_QUERY_PARAM_STYLE

Show more

multi-pairs, comma-separated, array-pairs

Set whether hostname verification is enabled. Default is enabled. This setting should not be disabled in production as it makes the client vulnerable to MITM attacks.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_VERIFY_HOST

Show more

boolean

The trust store location. Can point to either a classpath resource or a file.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_TRUST_STORE

Show more

string

The trust store password.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_TRUST_STORE_PASSWORD

Show more

string

The type of the trust store. Defaults to "JKS".

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_TRUST_STORE_TYPE

Show more

string

The key store location. Can point to either a classpath resource or a file.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_KEY_STORE

Show more

string

The key store password.

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_KEY_STORE_PASSWORD

Show more

string

The type of the key store. Defaults to "JKS".

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_KEY_STORE_TYPE

Show more

string

The name of the TLS configuration to use.

If not set and the default TLS configuration is configured (quarkus.tls.*) then that will be used. If a name is configured, it uses the configuration from quarkus.tls.<name>.* If a name is configured, but no TLS configuration is found with that name then an error will be thrown.

If no TLS configuration is set, then the keys-tore, trust-store, etc. properties will be used.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT_TLS_CONFIGURATION_NAME

Show more

string

If this is true then HTTP/2 will be enabled.

Environment variable: QUARKUS_REST_CLIENT_HTTP2

Show more

boolean

false

The max HTTP chunk size (8096 bytes by default).

Can be overwritten by client-specific settings.

Environment variable: QUARKUS_REST_CLIENT_MAX_CHUNK_SIZE

Show more

MemorySize 

8k

If the Application-Layer Protocol Negotiation is enabled, the client will negotiate which protocol to use over the protocols exposed by the server. By default, it will try to use HTTP/2 first and if it’s not enabled, it will use HTTP/1.1. When the property http2 is enabled, this flag will be automatically enabled.

Environment variable: QUARKUS_REST_CLIENT_ALPN

Show more

boolean

If true, the stacktrace of the invocation of the REST Client method is captured. This stacktrace will be used if the invocation throws an exception

Environment variable: QUARKUS_REST_CLIENT_CAPTURE_STACKTRACE

Show more

boolean

false

Scope of logging for the client.
WARNING: beware of logging sensitive data
The possible values are:

  • request-response - enables logging request and responses, including redirect responses

  • all - enables logging requests and responses and lower-level logging

  • none - no additional logging

This property is applicable to reactive REST clients only.

Environment variable: QUARKUS_REST_CLIENT_LOGGING_SCOPE

Show more

string

How many characters of the body should be logged. Message body can be large and can easily pollute the logs.

By default, set to 100.

This property is applicable to reactive REST clients only.

Environment variable: QUARKUS_REST_CLIENT_LOGGING_BODY_LIMIT

Show more

int

100

The CDI scope to use for injection. This property can contain either a fully qualified class name of a CDI scope annotation (such as "jakarta.enterprise.context.ApplicationScoped") or its simple name (such as "ApplicationScoped"). By default, this is not set which means the interface is not registered as a bean unless it is annotated with RegisterRestClient. If an interface is not annotated with RegisterRestClient and this property is set, then Quarkus will make the interface a bean of the configured scope.

Environment variable: QUARKUS_REST_CLIENT__CLIENTS__SCOPE

Show more

string

If set to true, then Quarkus will ensure that all calls from the REST client go through a local proxy server (that is managed by Quarkus). This can be very useful for capturing network traffic to a service that uses HTTPS.

This property is not applicable to the RESTEasy Client, only the Quarkus REST client (formerly RESTEasy Reactive client).

This property only applicable to dev and test mode.

Environment variable: QUARKUS_REST_CLIENT__CLIENTS__ENABLE_LOCAL_PROXY

Show more

boolean

false

This setting is used to select which proxy provider to use if there are multiple ones. It only applies if enable-local-proxy is true.

The algorithm for picking between multiple provider is the following:

  • If only the default is around, use it (its name is default)

  • If there is only one besides the default, use it

  • If there are multiple ones, fail

Environment variable: QUARKUS_REST_CLIENT__CLIENTS__LOCAL_PROXY_PROVIDER

Show more

string

If true, the extension will automatically remove the trailing slash in the paths if any. This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENTS__REMOVES_TRAILING_SLASH

Show more

boolean

true

The base URL to use for this service. This property or the uri property is considered required, unless the baseUri attribute is configured in the @RegisterRestClient annotation.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__URL

Show more

string

The base URI to use for this service. This property or the url property is considered required, unless the baseUri attribute is configured in the @RegisterRestClient annotation.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__URI

Show more

string

This property is only meant to be set by advanced configurations to override whatever value was set for the uri or url. The override is done using the REST Client class name configuration syntax.

This property is not applicable to the RESTEasy Client, only the Quarkus Rest client (formerly RESTEasy Reactive client).

Environment variable: QUARKUS_REST_CLIENT__CLIENT__OVERRIDE_URI

Show more

string

Map where keys are fully-qualified provider classnames to include in the client, and values are their integer priorities. The equivalent of the @RegisterProvider annotation.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__PROVIDERS

Show more

string

Timeout specified in milliseconds to wait to connect to the remote endpoint.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__CONNECT_TIMEOUT

Show more

long

Timeout specified in milliseconds to wait for a response from the remote endpoint.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__READ_TIMEOUT

Show more

long

A boolean value used to determine whether the client should follow HTTP redirect responses.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__FOLLOW_REDIRECTS

Show more

boolean

Mode in which the form data are encoded. Possible values are HTML5, RFC1738 and RFC3986. The modes are described in the Netty documentation

By default, Rest Client Reactive uses RFC1738.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__MULTIPART_POST_ENCODER_MODE

Show more

string

A string value in the form of : that specifies the HTTP proxy server hostname (or IP address) and port for requests of this client to use.

Use none to disable proxy

Environment variable: QUARKUS_REST_CLIENT__CLIENT__PROXY_ADDRESS

Show more

string

Proxy username.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__PROXY_USER

Show more

string

Proxy password.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__PROXY_PASSWORD

Show more

string

Hosts to access without proxy

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__NON_PROXY_HOSTS

Show more

string

An enumerated type string value with possible values of "MULTI_PAIRS" (default), "COMMA_SEPARATED", or "ARRAY_PAIRS" that specifies the format in which multiple values for the same query parameter is used.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__QUERY_PARAM_STYLE

Show more

multi-pairs, comma-separated, array-pairs

Set whether hostname verification is enabled. Default is enabled. This setting should not be disabled in production as it makes the client vulnerable to MITM attacks.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__VERIFY_HOST

Show more

boolean

The trust store location. Can point to either a classpath resource or a file.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__TRUST_STORE

Show more

string

The trust store password.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__TRUST_STORE_PASSWORD

Show more

string

The type of the trust store. Defaults to "JKS".

Environment variable: QUARKUS_REST_CLIENT__CLIENT__TRUST_STORE_TYPE

Show more

string

The key store location. Can point to either a classpath resource or a file.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__KEY_STORE

Show more

string

The key store password.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__KEY_STORE_PASSWORD

Show more

string

The type of the key store. Defaults to "JKS".

Environment variable: QUARKUS_REST_CLIENT__CLIENT__KEY_STORE_TYPE

Show more

string

The class name of the host name verifier. The class must have a public no-argument constructor.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__HOSTNAME_VERIFIER

Show more

string

The name of the TLS configuration to use.

If not set and the default TLS configuration is configured (quarkus.tls.*) then that will be used. If a name is configured, it uses the configuration from quarkus.tls.<name>.* If a name is configured, but no TLS configuration is found with that name then an error will be thrown.

If no TLS configuration is set, then the keys-tore, trust-store, etc. properties will be used.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__TLS_CONFIGURATION_NAME

Show more

string

The time in ms for which a connection remains unused in the connection pool before being evicted and closed. A timeout of 0 means there is no timeout.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__CONNECTION_TTL

Show more

int

The size of the connection pool for this client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__CONNECTION_POOL_SIZE

Show more

int

If set to false disables the keep alive completely.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__KEEP_ALIVE_ENABLED

Show more

boolean

The maximum number of redirection a request can follow.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__MAX_REDIRECTS

Show more

int

The HTTP headers that should be applied to all requests of the rest client.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__HEADERS__HEADER_NAME_

Show more

Map<String,String>

Set to true to share the HTTP client between REST clients. There can be multiple shared clients distinguished by name, when no specific name is set, the name __vertx.DEFAULT is used.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__SHARED

Show more

boolean

Set the HTTP client name, used when the client is shared, otherwise ignored.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__NAME

Show more

string

Configure the HTTP user-agent header to use.

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__USER_AGENT

Show more

string

If this is true then HTTP/2 will be enabled.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__HTTP2

Show more

boolean

The max HTTP ch unk size (8096 bytes by default).

This property is not applicable to the RESTEasy Client.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__MAX_CHUNK_SIZE

Show more

MemorySize 

8K

If the Application-Layer Protocol Negotiation is enabled, the client will negotiate which protocol to use over the protocols exposed by the server. By default, it will try to use HTTP/2 first and if it’s not enabled, it will use HTTP/1.1. When the property http2 is enabled, this flag will be automatically enabled.

Environment variable: QUARKUS_REST_CLIENT__CLIENT__ALPN

Show more

boolean

If true, the stacktrace of the invocation of the REST Client method is captured. This stacktrace will be used if the invocation throws an exception

Environment variable: QUARKUS_REST_CLIENT__CLIENT__CAPTURE_STACKTRACE

Show more

boolean

About the MemorySize format

A size configuration option recognizes strings in this format (shown as a regular expression): [0-9]+[KkMmGgTtPpEeZzYy]?.

If no suffix is given, assume bytes.

Conteúdo Relacionado