docs
reference
tessl install tessl/maven-io-quarkus--quarkus-resteasy-reactive@3.15.0A Jakarta REST implementation utilizing build time processing and Vert.x for high-performance REST endpoints with reactive capabilities in cloud-native environments.
Complex implementation patterns for sophisticated use cases.
Implement resilience with circuit breaker:
@Path("/api/external")
public class ExternalServiceResource {
@Inject
@RestClient
ExternalApiClient externalClient;
private final CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("external-api");
@GET
@Path("/data")
public Uni<RestResponse<Data>> getData() {
return Uni.createFrom().item(() ->
circuitBreaker.executeSupplier(() ->
externalClient.getData().await().indefinitely()
)
)
.onItem().transform(data -> RestResponse.ok(data))
.onFailure(CallNotPermittedException.class)
.recoverWithItem(RestResponse.status(503, "Service temporarily unavailable"));
}
}Implement event-driven architecture:
@Path("/api/orders")
public class OrderResource {
@Inject
OrderEventStore eventStore;
@Inject
OrderProjection projection;
@POST
public Uni<RestResponse<Order>> createOrder(CreateOrderCommand command) {
OrderCreatedEvent event = new OrderCreatedEvent(
UUID.randomUUID().toString(),
command.customerId,
command.items,
Instant.now()
);
return eventStore.append(event)
.chain(() -> projection.apply(event))
.onItem().transform(order -> RestResponse.status(201, order));
}
@GET
@Path("/{id}")
public Uni<RestResponse<Order>> getOrder(@RestPath String id) {
return eventStore.getEvents(id)
.collect().asList()
.map(events -> projection.rebuild(events))
.onItem().transform(order ->
order != null
? RestResponse.ok(order)
: RestResponse.notFound()
);
}
}Separate read and write models:
// Command side
@Path("/api/commands/products")
public class ProductCommandResource {
@Inject
ProductCommandService commandService;
@POST
public Uni<CommandResult> createProduct(CreateProductCommand command) {
return commandService.handle(command);
}
@PUT
@Path("/{id}")
public Uni<CommandResult> updateProduct(
@RestPath String id,
UpdateProductCommand command
) {
return commandService.handle(command.withId(id));
}
}
// Query side
@Path("/api/queries/products")
public class ProductQueryResource {
@Inject
ProductQueryService queryService;
@GET
public Multi<ProductView> list(@RestQuery Optional<String> category) {
return queryService.findAll(category);
}
@GET
@Path("/{id}")
public Uni<ProductView> get(@RestPath String id) {
return queryService.findById(id);
}
}Distributed transaction coordination:
@ApplicationScoped
public class OrderSaga {
@Inject
OrderService orderService;
@Inject
PaymentService paymentService;
@Inject
InventoryService inventoryService;
@Inject
ShippingService shippingService;
public Uni<OrderResult> executeOrderSaga(CreateOrderRequest request) {
return createOrder(request)
.chain(order -> reserveInventory(order)
.chain(reserved -> processPayment(order)
.chain(paid -> scheduleShipping(order)
.onItem().transform(shipped ->
new OrderResult(order, OrderStatus.COMPLETED)
)
.onFailure().call(ex ->
compensatePayment(order)
.chain(() -> compensateInventory(order))
)
)
.onFailure().call(ex -> compensateInventory(order))
)
.onFailure().call(ex -> compensateOrder(order))
);
}
private Uni<Order> createOrder(CreateOrderRequest request) {
return orderService.create(request);
}
private Uni<Void> reserveInventory(Order order) {
return inventoryService.reserve(order.getItems());
}
private Uni<Void> processPayment(Order order) {
return paymentService.charge(order.getTotal());
}
private Uni<Void> scheduleShipping(Order order) {
return shippingService.schedule(order);
}
private Uni<Void> compensateOrder(Order order) {
return orderService.cancel(order.getId());
}
private Uni<Void> compensateInventory(Order order) {
return inventoryService.release(order.getItems());
}
private Uni<Void> compensatePayment(Order order) {
return paymentService.refund(order.getTotal());
}
}Dynamic field selection:
@Path("/api/users")
public class UserResource {
@Inject
UserService userService;
@GET
@Path("/{id}")
public Uni<JsonObject> get(
@RestPath Long id,
@RestQuery Optional<String> fields
) {
return userService.findById(id)
.onItem().transform(user -> {
Set<String> selectedFields = fields
.map(f -> Set.of(f.split(",")))
.orElse(Set.of("id", "name", "email"));
JsonObjectBuilder builder = Json.createObjectBuilder();
if (selectedFields.contains("id")) {
builder.add("id", user.id);
}
if (selectedFields.contains("name")) {
builder.add("name", user.name);
}
if (selectedFields.contains("email")) {
builder.add("email", user.email);
}
if (selectedFields.contains("profile")) {
builder.add("profile", toJson(user.profile));
}
return builder.build();
});
}
}Real-time data aggregation:
@Path("/api/analytics")
public class AnalyticsResource {
@Inject
EventService eventService;
@GET
@Path("/stream")
@Produces(MediaType.SERVER_SENT_EVENTS)
@RestStreamElementType(MediaType.APPLICATION_JSON)
public Multi<AggregatedMetrics> streamMetrics() {
return eventService.streamEvents()
.group().intoLists().of(100, Duration.ofSeconds(5))
.onItem().transform(events -> {
AggregatedMetrics metrics = new AggregatedMetrics();
metrics.count = events.size();
metrics.avgValue = events.stream()
.mapToDouble(Event::getValue)
.average()
.orElse(0.0);
metrics.maxValue = events.stream()
.mapToDouble(Event::getValue)
.max()
.orElse(0.0);
return metrics;
});
}
}ETags and conditional requests:
@Path("/api/documents")
public class DocumentResource {
@Inject
DocumentService documentService;
@GET
@Path("/{id}")
public Response get(
@RestPath Long id,
@Context Request request
) {
Document doc = documentService.findById(id);
if (doc == null) {
return Response.status(404).build();
}
// Generate ETag from version
EntityTag etag = new EntityTag(doc.getVersion());
// Check If-None-Match
Response.ResponseBuilder builder = request.evaluatePreconditions(etag);
if (builder != null) {
return builder.build(); // 304 Not Modified
}
return Response.ok(doc)
.tag(etag)
.lastModified(doc.getUpdatedAt())
.build();
}
@PUT
@Path("/{id}")
public Response update(
@RestPath Long id,
@RestHeader("If-Match") String ifMatch,
Document document
) {
Document existing = documentService.findById(id);
if (existing == null) {
return Response.status(404).build();
}
// Check If-Match for optimistic locking
if (!existing.getVersion().equals(ifMatch)) {
return Response.status(412) // Precondition Failed
.entity("Document was modified by another user")
.build();
}
Document updated = documentService.update(id, document);
return Response.ok(updated)
.tag(new EntityTag(updated.getVersion()))
.build();
}
}Tenant isolation:
@ApplicationScoped
public class TenantFilter {
@ServerRequestFilter(priority = Priorities.AUTHENTICATION + 1)
public void extractTenant(
ContainerRequestContext ctx,
@RestHeader("X-Tenant-ID") Optional<String> tenantId
) {
String tenant = tenantId.orElse("default");
TenantContext.set(tenant);
}
@ServerResponseFilter
public void clearTenant() {
TenantContext.clear();
}
}
@Path("/api/data")
public class DataResource {
@Inject
DataService dataService;
@GET
public Uni<List<Data>> list() {
String tenant = TenantContext.get();
return dataService.findByTenant(tenant);
}
}API versioning via Accept header:
@Path("/api/products")
public class ProductResource {
@Inject
ProductService productService;
@GET
@Path("/{id}")
public Response get(
@RestPath Long id,
@RestHeader("Accept") String accept
) {
Product product = productService.findById(id);
if (product == null) {
return Response.status(404).build();
}
if (accept.contains("application/vnd.api.v2+json")) {
return Response.ok(toV2DTO(product))
.type("application/vnd.api.v2+json")
.build();
}
return Response.ok(toV1DTO(product))
.type("application/vnd.api.v1+json")
.build();
}
}Implement reactive caching layer:
@ApplicationScoped
public class CachedProductService {
@Inject
ProductService productService;
private final Cache<Long, Product> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(Duration.ofMinutes(10))
.build();
public Uni<Product> findById(Long id) {
Product cached = cache.getIfPresent(id);
if (cached != null) {
return Uni.createFrom().item(cached);
}
return productService.findById(id)
.onItem().invoke(product -> cache.put(id, product));
}
public Uni<Product> update(Long id, Product product) {
return productService.update(id, product)
.onItem().invoke(updated -> {
cache.invalidate(id);
cache.put(id, updated);
});
}
}