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.

reactive-programming.mddocs/guides/

Reactive Programming Guide

Learn how to build reactive, non-blocking REST endpoints with Mutiny.

Why Reactive?

  • Non-blocking I/O: Better resource utilization
  • Scalability: Handle more concurrent requests
  • Backpressure: Control data flow
  • Composability: Chain async operations

Uni - Single Async Value

Basic Uni

import io.smallrye.mutiny.Uni;

@GET
@Path("/{id}")
public Uni<Item> get(@RestPath Long id) {
    return itemService.findByIdAsync(id);
}

Creating Uni

// From item
Uni<String> uni = Uni.createFrom().item("Hello");

// From supplier
Uni<String> uni = Uni.createFrom().item(() -> expensiveOperation());

// From CompletionStage
Uni<String> uni = Uni.createFrom().completionStage(future);

// From failure
Uni<String> uni = Uni.createFrom().failure(new RuntimeException("Error"));

Transforming Uni

@GET
@Path("/{id}")
public Uni<ItemDTO> get(@RestPath Long id) {
    return itemService.findByIdAsync(id)
        .onItem().transform(item -> new ItemDTO(item));
}

Chaining Operations

@POST
public Uni<Item> create(CreateItemRequest request) {
    return itemService.createAsync(request)
        .chain(item -> auditService.logCreationAsync(item))
        .onItem().transform(item -> item);
}

Error Handling

@GET
@Path("/{id}")
public Uni<RestResponse<Item>> get(@RestPath Long id) {
    return itemService.findByIdAsync(id)
        .onItem().transform(item -> RestResponse.ok(item))
        .onFailure().recoverWithItem(
            ex -> RestResponse.status(500, "Error: " + ex.getMessage())
        );
}

Retry Logic

@GET
@Path("/{id}")
public Uni<Item> get(@RestPath Long id) {
    return itemService.findByIdAsync(id)
        .onFailure().retry().atMost(3)
        .onFailure().retry().withBackOff(Duration.ofSeconds(1));
}

Timeout

@GET
@Path("/{id}")
public Uni<Item> get(@RestPath Long id) {
    return itemService.findByIdAsync(id)
        .ifNoItem().after(Duration.ofSeconds(5))
        .fail();
}

Multi - Stream of Values

Basic Multi

@GET
@Path("/stream")
@Produces(MediaType.SERVER_SENT_EVENTS)
public Multi<Item> stream() {
    return itemService.streamAll();
}

Creating Multi

// From items
Multi<String> multi = Multi.createFrom().items("a", "b", "c");

// From iterable
Multi<String> multi = Multi.createFrom().iterable(list);

// From ticks
Multi<Long> multi = Multi.createFrom().ticks()
    .every(Duration.ofSeconds(1));

Transforming Multi

@GET
@Path("/stream")
public Multi<ItemDTO> stream() {
    return itemService.streamAll()
        .onItem().transform(item -> new ItemDTO(item));
}

Filtering

@GET
@Path("/stream/active")
public Multi<Item> streamActive() {
    return itemService.streamAll()
        .filter(item -> item.isActive());
}

Limiting

@GET
@Path("/stream/top10")
public Multi<Item> streamTop10() {
    return itemService.streamAll()
        .select().first(10);
}

Combining Async Operations

Combine Multiple Unis

@GET
@Path("/{id}/full")
public Uni<FullItem> getFull(@RestPath Long id) {
    Uni<Item> itemUni = itemService.findByIdAsync(id);
    Uni<List<Review>> reviewsUni = reviewService.findByItemIdAsync(id);
    Uni<Inventory> inventoryUni = inventoryService.findByItemIdAsync(id);
    
    return Uni.combine().all()
        .unis(itemUni, reviewsUni, inventoryUni)
        .asTuple()
        .onItem().transform(tuple -> 
            new FullItem(tuple.getItem1(), tuple.getItem2(), tuple.getItem3())
        );
}

Combine with Combinator

@GET
@Path("/{id}/summary")
public Uni<Summary> getSummary(@RestPath Long id) {
    return Uni.combine().all()
        .unis(
            itemService.findByIdAsync(id),
            statsService.getStatsAsync(id)
        )
        .with((item, stats) -> new Summary(item, stats));
}

RestMulti - Streaming with Headers

Basic RestMulti

@GET
@Path("/stream")
@Produces(MediaType.APPLICATION_JSON)
public Multi<Item> stream() {
    return RestMulti.fromMultiData(itemService.streamAll())
        .status(200)
        .header("X-Stream-Type", "items")
        .build();
}

From Uni Response

@GET
@Path("/user/{id}/events")
public Multi<Event> streamUserEvents(@RestPath Long id) {
    return RestMulti.fromUniResponse(
        userService.findByIdAsync(id),
        user -> eventService.streamEventsForUser(user.getId())
    );
}

Server-Sent Events

JSON Events

@GET
@Path("/notifications")
@Produces(MediaType.SERVER_SENT_EVENTS)
@RestStreamElementType(MediaType.APPLICATION_JSON)
public Multi<Notification> streamNotifications() {
    return notificationService.streamForCurrentUser();
}

Text Events

@GET
@Path("/logs")
@Produces(MediaType.SERVER_SENT_EVENTS)
public Multi<String> streamLogs() {
    return logService.tailLogs();
}

Backpressure

Buffer Overflow Strategy

@GET
@Path("/stream")
public Multi<Item> stream() {
    return itemService.streamAll()
        .onOverflow().buffer(100)
        .onOverflow().drop();
}

Demand Control

@GET
@Path("/stream")
public Multi<Item> stream() {
    return RestMulti.fromMultiData(itemService.streamAll())
        .withDemand(10)  // Process 10 items concurrently
        .build();
}

Database Integration

Hibernate Reactive

@Inject
Mutiny.SessionFactory sessionFactory;

@GET
@Path("/{id}")
public Uni<Item> get(@RestPath Long id) {
    return sessionFactory.withSession(session ->
        session.find(Item.class, id)
    );
}

@POST
public Uni<Item> create(Item item) {
    return sessionFactory.withTransaction((session, tx) ->
        session.persist(item)
            .replaceWith(item)
    );
}

Panache Reactive

@GET
@Path("/{id}")
public Uni<Item> get(@RestPath Long id) {
    return Item.findById(id);
}

@GET
public Multi<Item> list() {
    return Item.streamAll();
}

Best Practices

  1. Use Uni for Single Values: Don't block on Uni
  2. Use Multi for Streams: Leverage backpressure
  3. Handle Errors: Always add error handlers
  4. Set Timeouts: Prevent hanging requests
  5. Use Retry: For transient failures
  6. Compose Operations: Chain transformations
  7. Test Reactively: Use Uni/Multi test utilities

Common Patterns

Load and Transform

return itemService.findByIdAsync(id)
    .onItem().transform(this::toDTO);

Load and Enrich

return itemService.findByIdAsync(id)
    .chain(item -> enrichmentService.enrichAsync(item));

Parallel Loading

return Uni.combine().all()
    .unis(service1.loadAsync(), service2.loadAsync())
    .asTuple();

Sequential with Dependency

return userService.findByIdAsync(userId)
    .chain(user -> orderService.findByUserAsync(user));

Next Steps

  • Build REST Clients with reactive support
  • Review Streaming Reference
  • Check Common Scenarios
  • Explore Advanced Patterns