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-clients.mddocs/guides/

REST Clients Guide

Learn how to build type-safe, declarative REST clients with Quarkus.

Add REST Client Extension

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest-client-reactive</artifactId>
</dependency>

Basic REST Client

Define Client Interface

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

@Path("/api/users")
@RegisterRestClient(configKey = "user-api")
public interface UserClient {
    
    @GET
    @Path("/{id}")
    Uni<User> getUser(@PathParam("id") Long id);
    
    @GET
    Uni<List<User>> listUsers();
    
    @POST
    Uni<User> createUser(User user);
    
    @DELETE
    @Path("/{id}")
    Uni<Void> deleteUser(@PathParam("id") Long id);
}

Configuration

# Base URL
quarkus.rest-client.user-api.url=https://api.example.com

# Timeouts
quarkus.rest-client.user-api.connect-timeout=5000
quarkus.rest-client.user-api.read-timeout=30000

Use the Client

@Inject
@RestClient
UserClient userClient;

@GET
@Path("/users/{id}")
public Uni<User> getUser(@RestPath Long id) {
    return userClient.getUser(id);
}

Programmatic Client Creation

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

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

Query Parameters

Static Query Parameters

@GET
@Path("/search")
@ClientQueryParam(name = "api_key", value = "${api.key}")
@ClientQueryParam(name = "version", value = "2")
Uni<List<Result>> search(@QueryParam("q") String query);

Dynamic Query Parameters

@GET
@Path("/search")
Uni<List<Result>> search(
    @QueryParam("q") String query,
    @QueryParam("page") int page,
    @QueryParam("size") int size
);

Headers

Static Headers

@GET
@Path("/data")
@ClientHeaderParam(name = "X-API-Key", value = "${api.key}")
@ClientHeaderParam(name = "User-Agent", value = "MyApp/1.0")
Uni<Data> getData();

Dynamic Headers

@GET
@Path("/data")
Uni<Data> getData(@HeaderParam("Authorization") String token);

Header Factory

@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;
            });
    }
}

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

Authentication

Basic Authentication

@RegisterRestClient
@ClientBasicAuth(username = "${api.username}", password = "${api.password}")
public interface SecureClient {
    @GET
    @Path("/data")
    Uni<Data> getData();
}

Bearer Token

@GET
@Path("/data")
Uni<Data> getData(@HeaderParam("Authorization") String bearerToken);

// Usage
String token = "Bearer " + tokenService.getToken();
client.getData(token);

Error Handling

Exception Mapper

@RegisterRestClient
public interface ApiClient {
    
    @GET
    @Path("/users/{id}")
    Uni<User> getUser(@PathParam("id") Long id);
    
    @ClientExceptionMapper
    static RuntimeException toException(Response response) {
        if (response.getStatus() == 404) {
            return new UserNotFoundException();
        }
        if (response.getStatus() == 401) {
            return new UnauthorizedException();
        }
        return new ApiException("HTTP " + response.getStatus());
    }
}

Handling Errors

@GET
@Path("/users/{id}")
public Uni<RestResponse<User>> getUser(@RestPath Long id) {
    return userClient.getUser(id)
        .onItem().transform(user -> RestResponse.ok(user))
        .onFailure(UserNotFoundException.class)
        .recoverWithItem(RestResponse.status(404, "User not found"));
}

Multipart Upload

@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 = client.upload(form);

SSL/TLS Configuration

Trust Store

quarkus.rest-client.user-api.trust-store=/path/to/truststore.jks
quarkus.rest-client.user-api.trust-store-password=password
quarkus.rest-client.user-api.verify-host=true

Programmatic SSL

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

quarkus.rest-client.user-api.proxy-address=proxy.corp.com:8080
quarkus.rest-client.user-api.proxy-user=proxyuser
quarkus.rest-client.user-api.proxy-password=proxypass
quarkus.rest-client.user-api.non-proxy-hosts=localhost

Retry and Timeout

Retry Logic

@GET
@Path("/{id}")
public Uni<User> getUser(@RestPath Long id) {
    return userClient.getUser(id)
        .onFailure().retry().atMost(3)
        .onFailure().retry().withBackOff(Duration.ofSeconds(1));
}

Timeout

@GET
@Path("/{id}")
public Uni<User> getUser(@RestPath Long id) {
    return userClient.getUser(id)
        .ifNoItem().after(Duration.ofSeconds(5))
        .fail();
}

Testing REST Clients

Mock with WireMock

@QuarkusTest
@QuarkusTestResource(WireMockTestResource.class)
class UserClientTest {
    
    @Inject
    @RestClient
    UserClient userClient;
    
    @Test
    void testGetUser() {
        // Setup WireMock stub
        stubFor(get(urlEqualTo("/api/users/1"))
            .willReturn(aResponse()
                .withStatus(200)
                .withHeader("Content-Type", "application/json")
                .withBody("{\"id\":1,\"name\":\"John\"}")));
        
        // Test
        User user = userClient.getUser(1L).await().indefinitely();
        assertEquals("John", user.name);
    }
}

Best Practices

  1. Use Reactive Types: Always return Uni or Multi
  2. Handle Errors: Implement exception mappers
  3. Set Timeouts: Prevent hanging requests
  4. Use Configuration: Externalize URLs and credentials
  5. Implement Retry: For transient failures
  6. Test with Mocks: Use WireMock for testing
  7. Secure Connections: Use HTTPS and verify certificates

Next Steps

  • Review REST Client Reference
  • Check Common Scenarios
  • Explore Advanced Patterns