or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/io.quarkus/quarkus-resteasy-reactive@3.15.x

docs

index.md
tile.json

tessl/maven-io-quarkus--quarkus-resteasy-reactive

tessl install tessl/maven-io-quarkus--quarkus-resteasy-reactive@3.15.0

A Jakarta REST implementation utilizing build time processing and Vert.x for high-performance REST endpoints with reactive capabilities in cloud-native environments.

rest-client.mddocs/reference/

REST Client

Quarkus REST Client provides a type-safe, declarative way to invoke REST services. It combines standard Jakarta REST Client APIs with Quarkus-specific enhancements for reactive programming, custom headers, authentication, and flexible configuration.

Import

import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder;
import io.quarkus.rest.client.reactive.ClientExceptionMapper;
import io.quarkus.rest.client.reactive.ClientQueryParam;
import io.quarkus.rest.client.reactive.ClientQueryParams;
import io.quarkus.rest.client.reactive.ClientFormParam;
import io.quarkus.rest.client.reactive.ClientFormParams;
import io.quarkus.rest.client.reactive.ClientBasicAuth;
import io.quarkus.rest.client.reactive.ClientRedirectHandler;
import io.quarkus.rest.client.reactive.NotBody;
import io.quarkus.rest.client.reactive.HeaderFiller;
import io.quarkus.rest.client.reactive.ReactiveClientHeadersFactory;
import io.quarkus.rest.client.reactive.ComputedParamContext;
import org.jboss.resteasy.reactive.client.api.ClientMultipartForm;
import jakarta.ws.rs.*;
import io.smallrye.mutiny.Uni;

QuarkusRestClientBuilder

Main entry point for building type-safe REST clients programmatically.

public interface QuarkusRestClientBuilder {
    // Factory method
    static QuarkusRestClientBuilder newBuilder();

    // Base URL configuration
    QuarkusRestClientBuilder baseUrl(URL url);
    QuarkusRestClientBuilder baseUri(URI uri);

    // Timeout configuration
    QuarkusRestClientBuilder connectTimeout(long timeout, TimeUnit unit);
    QuarkusRestClientBuilder readTimeout(long timeout, TimeUnit unit);

    // TLS/SSL configuration
    QuarkusRestClientBuilder tlsConfiguration(TlsConfiguration tlsConfiguration);
    QuarkusRestClientBuilder sslContext(SSLContext sslContext);
    QuarkusRestClientBuilder verifyHost(boolean verifyHost);
    QuarkusRestClientBuilder trustStore(KeyStore trustStore);
    QuarkusRestClientBuilder trustStore(KeyStore trustStore, String trustStorePassword);
    QuarkusRestClientBuilder keyStore(KeyStore keyStore, String keystorePassword);
    QuarkusRestClientBuilder hostnameVerifier(HostnameVerifier hostnameVerifier);
    QuarkusRestClientBuilder trustAll(boolean trustAll);

    // Proxy configuration
    QuarkusRestClientBuilder proxyAddress(String proxyHost, int proxyPort);
    QuarkusRestClientBuilder proxyUser(String proxyUser);
    QuarkusRestClientBuilder proxyPassword(String proxyPassword);
    QuarkusRestClientBuilder nonProxyHosts(String nonProxyHosts);

    // HTTP client options
    QuarkusRestClientBuilder followRedirects(boolean follow);
    QuarkusRestClientBuilder multipartPostEncoderMode(String mode);
    QuarkusRestClientBuilder queryParamStyle(QueryParamStyle style);
    QuarkusRestClientBuilder userAgent(String userAgent);

    // Headers and logging
    QuarkusRestClientBuilder clientHeadersFactory(Class<? extends ClientHeadersFactory> clientHeadersFactoryClass);
    QuarkusRestClientBuilder clientHeadersFactory(ClientHeadersFactory clientHeadersFactory);
    QuarkusRestClientBuilder httpClientOptions(Class<? extends HttpClientOptions> httpClientOptionsClass);
    QuarkusRestClientBuilder httpClientOptions(HttpClientOptions httpClientOptions);
    QuarkusRestClientBuilder clientLogger(ClientLogger clientLogger);
    QuarkusRestClientBuilder loggingScope(LoggingScope loggingScope);
    QuarkusRestClientBuilder loggingBodyLimit(Integer limit);

    // Build client
    <T> T build(Class<T> clazz);
}

Client Annotations

@ClientQueryParam

Adds query parameters to client requests.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(ClientQueryParams.class)
public @interface ClientQueryParam {
    String name();                  // Query parameter name
    String[] value();               // Query parameter value(s)
    boolean required() default true;  // Whether parameter is required
}

@ClientQueryParams

Container for multiple @ClientQueryParam annotations.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ClientQueryParams {
    ClientQueryParam[] value();
}

@ClientFormParam

Adds form parameters to client requests.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(ClientFormParams.class)
public @interface ClientFormParam {
    String name();                  // Form parameter name
    String[] value();               // Form parameter value(s)
    boolean required() default true;  // Whether parameter is required
}

@ClientFormParams

Container for multiple @ClientFormParam annotations.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ClientFormParams {
    ClientFormParam[] value();
}

@ClientBasicAuth

Configures HTTP Basic Authentication for client.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ClientBasicAuth {
    String username();  // Username
    String password();  // Password
}

@ClientExceptionMapper

Maps client-side HTTP errors to custom exceptions.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClientExceptionMapper {
    int priority() default Priorities.USER;  // Mapper priority
}

@ClientRedirectHandler

Custom redirect handling for client requests. Must be placed on a static method that returns a URI subclass.

Method Requirements:

  • Must be a static method
  • Must return java.net.URI (or subclass)
  • Must take exactly ONE parameter of type:
    • jakarta.ws.rs.core.Response - The HTTP response triggering the redirect, OR
    • java.lang.reflect.Method - The client interface method being invoked
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClientRedirectHandler {
    int priority() default Priorities.USER;  // Handler priority
}

@NotBody

Marks a parameter as not being the request body.

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface NotBody {
}

Client Interfaces

ReactiveClientHeadersFactory

Abstract class for reactive header generation.

public abstract class ReactiveClientHeadersFactory extends ClientHeadersFactory {
    /**
     * Generate headers asynchronously
     * @param incomingHeaders Headers from incoming request
     * @param clientOutgoingHeaders Headers configured on client
     * @return Uni with headers to add to outgoing request
     */
    public abstract Uni<MultivaluedMap<String, String>> getHeaders(
        MultivaluedMap<String, String> incomingHeaders,
        MultivaluedMap<String, String> clientOutgoingHeaders
    );

    /**
     * Blocking version throws exception (use getHeaders instead)
     */
    @Override
    public final MultivaluedMap<String, String> update(
        MultivaluedMap<String, String> incomingHeaders,
        MultivaluedMap<String, String> clientOutgoingHeaders
    );
}

HeaderFiller

Interface for adding headers to client requests.

public interface HeaderFiller {
    void addHeaders(MultivaluedMap<String, String> headers);
}

ExtendedHeaderFiller

Extended version of HeaderFiller with access to the request context for more advanced header generation.

public interface ExtendedHeaderFiller extends HeaderFiller {
    /**
     * Add headers to the request with access to request context
     * @param headers The header map to populate
     * @param requestContext The client request context
     */
    void addHeaders(
        MultivaluedMap<String, String> headers,
        ResteasyReactiveClientRequestContext requestContext
    );
}

ComputedParamContext

Context for computed client parameters.

public interface ComputedParamContext {
    String name();  // Parameter name
    List<MethodParameter> methodParameters();  // Method parameters

    interface MethodParameter {
        Object value();  // Parameter value
    }
}

ClientLogger

Interface for custom client request/response logging.

public interface ClientLogger {
    void setBodySize(int bodySize);
    void logResponse(HttpClientResponse response, boolean redirect);
    void logRequest(HttpClientRequest request, Buffer body, boolean omitBody);
}

LoggingScope

Enum specifying the scope of client logging.

public enum LoggingScope {
    NONE,                 // No logging
    REQUEST_RESPONSE,     // Log request and response metadata
    ALL;                  // Log everything including bodies
}

QueryParamStyle

Enum from MicroProfile REST Client for query parameter encoding style.

// From org.eclipse.microprofile.rest.client.ext.QueryParamStyle
public enum QueryParamStyle {
    MULTI_PAIRS,    // Encode multi-valued params as separate name=value pairs
    COMMA_SEPARATED, // Encode multi-valued params as name=value1,value2
    ARRAY_PAIRS;    // Encode multi-valued params as name[]=value1&name[]=value2
}

TlsConfiguration

Interface from Quarkus TLS registry for advanced TLS configuration. Pass to tlsConfiguration() method.

// From io.quarkus.tls.TlsConfiguration
public interface TlsConfiguration {
    KeyStore getKeyStore();
    KeyCertOptions getKeyStoreOptions();
    KeyStore getTrustStore();
    TrustOptions getTrustStoreOptions();
    SSLOptions getSSLOptions();
    SSLContext createSSLContext() throws Exception;
    Optional<String> getHostnameVerificationAlgorithm();
    boolean usesSni();
    boolean isTrustAll();
    boolean reload();
}

HttpClientOptions

Vert.x HTTP client options for advanced client configuration. Pass to httpClientOptions() method or implement a custom resolver.

Note: This is a Vert.x type (io.vertx.core.http.HttpClientOptions). Refer to Vert.x documentation for available options.

ClientMultipartForm

Client-side multipart form builder.

public abstract class ClientMultipartForm {
    // Factory method
    public static ClientMultipartForm create();

    // Charset configuration
    public ClientMultipartForm setCharset(String charset);
    public ClientMultipartForm setCharset(Charset charset);
    public Charset getCharset();

    // Add form parts
    public ClientMultipartForm attribute(String name, String value, String filename);
    public ClientMultipartForm entity(String name, Object entity, String mediaType, Class<?> type);
    public ClientMultipartForm entity(String name, String filename, Object entity, String mediaType, Class<?> type);

    // File uploads
    public ClientMultipartForm textFileUpload(String name, String filename, String pathname, String mediaType);
    public ClientMultipartForm textFileUpload(String name, String filename, Buffer content, String mediaType);
    public ClientMultipartForm stringFileUpload(String name, String filename, String content, String mediaType);
    public ClientMultipartForm binaryFileUpload(String name, String filename, String pathname, String mediaType);
    public ClientMultipartForm binaryFileUpload(String name, String filename, Buffer content, String mediaType);
    public ClientMultipartForm multiAsBinaryFileUpload(String name, String filename, Multi<Byte> content, String mediaType);
    public ClientMultipartForm multiAsTextFileUpload(String name, String filename, Multi<Byte> content, String mediaType);
    public ClientMultipartForm fileUpload(FileUpload fileUpload);
}

Usage Examples

Basic REST Client

@Path("/api")
@RegisterRestClient(baseUri = "https://api.example.com")
public interface ApiClient {

    @GET
    @Path("/users/{id}")
    Uni<User> getUser(@PathParam("id") String id);

    @POST
    @Path("/users")
    Uni<User> createUser(User user);

    @DELETE
    @Path("/users/{id}")
    Uni<Void> deleteUser(@PathParam("id") String id);
}

// Usage
@Inject
@RestClient
ApiClient apiClient;

public Uni<User> fetchUser(String id) {
    return apiClient.getUser(id);
}

Programmatic Client Creation

ApiClient client = QuarkusRestClientBuilder.newBuilder()
    .baseUri(URI.create("https://api.example.com"))
    .connectTimeout(5, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .build(ApiClient.class);

Uni<User> user = client.getUser("123");

Query Parameters

@Path("/api")
@RegisterRestClient
@ClientQueryParam(name = "api_key", value = "${api.key}")
public interface ApiClient {

    @GET
    @Path("/search")
    @ClientQueryParam(name = "type", value = "user")
    Uni<List<Result>> search(@QueryParam("q") String query);
}

Form Parameters

@Path("/api")
@RegisterRestClient
public interface AuthClient {

    @POST
    @Path("/login")
    @ClientFormParam(name = "grant_type", value = "password")
    Uni<Token> login(
        @FormParam("username") String username,
        @FormParam("password") String password
    );
}

Basic Authentication

@Path("/api")
@RegisterRestClient
@ClientBasicAuth(username = "${api.username}", password = "${api.password}")
public interface SecureApiClient {

    @GET
    @Path("/data")
    Uni<Data> getData();
}

Custom Exception Mapping

@Path("/api")
@RegisterRestClient
public interface ApiClient {

    @GET
    @Path("/users/{id}")
    Uni<User> getUser(@PathParam("id") String id);

    @ClientExceptionMapper
    static RuntimeException toException(Response response) {
        if (response.getStatus() == 404) {
            return new UserNotFoundException();
        }
        return new ApiException("HTTP " + response.getStatus());
    }
}

Reactive Headers

@ApplicationScoped
public class AuthHeaderFactory extends ReactiveClientHeadersFactory {

    @Inject
    TokenService tokenService;

    @Override
    public Uni<MultivaluedMap<String, String>> getHeaders(
        MultivaluedMap<String, String> incomingHeaders,
        MultivaluedMap<String, String> clientOutgoingHeaders
    ) {
        return tokenService.getTokenAsync()
            .map(token -> {
                MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
                headers.add("Authorization", "Bearer " + token);
                return headers;
            });
    }
}

@Path("/api")
@RegisterRestClient
@RegisterProvider(AuthHeaderFactory.class)
public interface SecureApiClient {
    @GET
    @Path("/data")
    Uni<Data> getData();
}

Multipart Upload (Client)

@Path("/api")
@RegisterRestClient
public interface FileApiClient {

    @POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    Uni<UploadResponse> upload(ClientMultipartForm form);
}

// Usage
ClientMultipartForm form = ClientMultipartForm.create()
    .attribute("description", "My file", null)
    .binaryFileUpload("file", "document.pdf", "/path/to/file.pdf", "application/pdf");

Uni<UploadResponse> response = fileApiClient.upload(form);

SSL Configuration

KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("truststore.jks"), "password".toCharArray());

ApiClient client = QuarkusRestClientBuilder.newBuilder()
    .baseUri(URI.create("https://secure-api.example.com"))
    .trustStore(trustStore, "password")
    .verifyHost(true)
    .build(ApiClient.class);

Proxy Configuration

ApiClient client = QuarkusRestClientBuilder.newBuilder()
    .baseUri(URI.create("https://api.example.com"))
    .proxyAddress("proxy.corp.com", 8080)
    .proxyUser("proxyuser")
    .proxyPassword("proxypass")
    .nonProxyHosts("localhost|*.internal")
    .build(ApiClient.class);

Redirect Handling

Using Response parameter (most common):

@Path("/api")
@RegisterRestClient
public interface ApiClient {

    @GET
    @Path("/resource")
    Uni<Data> getData();

    @ClientRedirectHandler
    static URI redirect(Response response) {
        // Custom redirect logic based on response
        if (response.getStatus() == 301) {
            String newLocation = response.getHeaderString("Location");
            return URI.create(newLocation);
        }
        return null;  // Use default handling
    }
}

Using Method parameter (for method-specific logic):

@Path("/api")
@RegisterRestClient
public interface ApiClient {

    @GET
    @Path("/resource")
    Uni<Data> getData();

    @ClientRedirectHandler
    static URI redirect(Method method) {
        // Custom redirect logic based on method
        if (method.getName().equals("getData")) {
            return URI.create("https://redirect.example.com/data");
        }
        return null;  // Use default handling
    }
}

Not Body Parameter

@Path("/api")
@RegisterRestClient
public interface ApiClient {

    @POST
    @Path("/upload")
    Uni<Response> upload(
        @NotBody @HeaderParam("X-File-Name") String filename,
        byte[] fileContent  // This is the body
    );
}

Configuration

Configure REST clients via application.properties:

# Base configuration
quarkus.rest-client."io.example.ApiClient".url=https://api.example.com
quarkus.rest-client."io.example.ApiClient".scope=jakarta.enterprise.context.ApplicationScoped

# Timeouts
quarkus.rest-client."io.example.ApiClient".connect-timeout=5000
quarkus.rest-client."io.example.ApiClient".read-timeout=30000

# Authentication
quarkus.rest-client."io.example.ApiClient".username=user
quarkus.rest-client."io.example.ApiClient".password=pass

# TLS
quarkus.rest-client."io.example.ApiClient".trust-store=/path/to/truststore.jks
quarkus.rest-client."io.example.ApiClient".trust-store-password=password
quarkus.rest-client."io.example.ApiClient".verify-host=true

# Proxy
quarkus.rest-client."io.example.ApiClient".proxy-address=proxy.corp.com:8080
quarkus.rest-client."io.example.ApiClient".proxy-user=proxyuser
quarkus.rest-client."io.example.ApiClient".proxy-password=proxypass
quarkus.rest-client."io.example.ApiClient".non-proxy-hosts=localhost

Best Practices

Always Use Reactive Types

// Good: Non-blocking
@GET
Uni<User> getUser(@PathParam("id") String id);

// Avoid: Blocking
@GET
User getUser(@PathParam("id") String id);

Handle Errors Properly

@ClientExceptionMapper
static RuntimeException mapException(Response response) {
    return switch (response.getStatus()) {
        case 404 -> new NotFoundException();
        case 401 -> new UnauthorizedException();
        case 403 -> new ForbiddenException();
        default -> new ApiException("HTTP " + response.getStatus());
    };
}

Use Configuration Over Hardcoding

// Good: Externalized configuration
@RegisterRestClient(configKey = "api-client")

// application.properties
// quarkus.rest-client.api-client.url=https://api.example.com

Implement Timeouts

QuarkusRestClientBuilder.newBuilder()
    .connectTimeout(5, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .build(ApiClient.class);