docs
reference
tessl install tessl/maven-io-quarkus--quarkus-rest@3.15.0A Jakarta REST implementation utilizing build time processing and Vert.x for high-performance REST endpoints with reactive programming support, security integration, and cloud-native features.
This document provides an overview of the Quarkus REST architecture, including the request lifecycle, handler chain, CDI integration, reactive layer, and Vert.x foundation.
Quarkus REST (formerly RESTEasy Reactive) is a modern Jakarta REST implementation built on reactive principles. It combines compile-time processing, reactive programming, and Vert.x's event loop for high performance with low resource consumption.
Key Architectural Principles:
┌─────────────────────────────────────────────┐
│ JAX-RS / Jakarta REST API │
│ (@Path, @GET, @POST, @Produces, etc.) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Quarkus REST Runtime Layer │
│ (Resource method invocation, parameter │
│ extraction, serialization) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Handler Chain Pipeline │
│ (Security, Observability, Compression) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ CDI / Arc Container │
│ (Dependency injection, producers) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Vert.x HTTP Server / Router │
│ (Event loop, routing, HTTP/2) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Netty (NIO) │
│ (Network I/O layer) │
└─────────────────────────────────────────────┘The complete flow of an HTTP request through Quarkus REST:
HTTP Request
↓
Netty NIO Thread
↓
Vert.x Event Loop
↓
Vert.x RouterThe request is received by Netty's NIO layer and dispatched to a Vert.x event loop thread.
Vert.x Router
↓
RestInitialHandler
↓
Route Matching (by path/method)
↓
QuarkusResteasyReactiveRequestContext createdThe Vert.x router matches the request to a REST route and creates the request context.
package io.quarkus.resteasy.reactive.server.runtime;
class QuarkusResteasyReactiveRequestContext extends ResteasyReactiveRequestContext {
protected void handleRequestScopeActivation();
protected void requestScopeDeactivated();
protected SecurityContext createSecurityContext();
}The request scope is activated, making CDI request-scoped beans available.
AFTER_PRE_MATCH handlers execute:
↓
- Early request filtering
- Request logging
- Protocol upgradesHandlers registered for the AFTER_PRE_MATCH phase execute.
Resource matching
↓
Resource class identified
↓
Resource method selected
↓
ServerResourceMethod resolvedThe framework matches the request to a specific resource method.
AFTER_MATCH handlers execute:
↓
- Security checks (EagerSecurityHandler)
↓
- Observability tracking (ObservabilityHandler)
↓
- Compression setup (ResteasyReactiveCompressionHandler)
↓
- Custom validatorsSecurity, observability, and other handlers execute before method invocation.
package io.quarkus.resteasy.reactive.server.runtime.security;
@Singleton
class EagerSecurityContext {
static EagerSecurityContext instance;
Uni<SecurityIdentity> getDeferredIdentity();
Uni<SecurityIdentity> getPermissionCheck(
ResteasyReactiveRequestContext requestContext,
SecurityIdentity identity
);
}Security checks are performed asynchronously using Mutiny Uni.
Extract method parameters:
↓
- @PathParam from URI path
- @QueryParam from query string
- @HeaderParam from headers
- @Context from CDI/JAX-RS context
- Request body deserializationMethod parameters are extracted and converted.
Invoke resource method
↓
Execute business logic
↓
Return response (Object, Response, Uni, Multi)The actual REST resource method executes.
AFTER_METHOD_INVOKE handlers execute:
↓
- WebSocket upgrade (if applicable)
- Response modification
- Response loggingPost-invocation handlers process the response.
Response object
↓
MessageBodyWriter selection
↓
Serialization (JSON, XML, etc.)
↓
HTTP response entityThe response is serialized using appropriate message body writers.
HTTP Response
↓
Compression (if enabled)
↓
Vert.x write to socket
↓
Netty NIO
↓
NetworkThe response is sent back to the client.
Request complete
↓
Closer cleanup (registered Closeables)
↓
Request scope deactivation
↓
CDI @Disposes methodsCleanup happens automatically through the Closer mechanism.
package io.quarkus.resteasy.reactive.server.runtime;
@Singleton
class QuarkusContextProducers {
@Produces
@RequestScoped
CloserImpl closer();
@Disposes
void closeCloser(CloserImpl closer);
}The handler chain is the core request processing pipeline.
package org.jboss.resteasy.reactive.server.spi;
interface ServerRestHandler {
void handle(ResteasyReactiveRequestContext requestContext) throws Exception;
}All handlers implement this simple interface.
enum Phase {
AFTER_PRE_MATCH, // Before resource matching
AFTER_MATCH, // After matching, before invocation
AFTER_METHOD_INVOKE // After invocation, before response
}package org.jboss.resteasy.reactive.server.handlers;
interface HandlerChainCustomizer {
List<ServerRestHandler> handlers(
Phase phase,
ResourceClass resourceClass,
ServerResourceMethod resourceMethod
);
}Applications can add custom handlers at each phase.
Security Handlers:
package io.quarkus.resteasy.reactive.server.runtime.security;
class EagerSecurityHandler implements ServerRestHandler {
void handle(ResteasyReactiveRequestContext requestContext);
}
class EagerSecurityInterceptorHandler implements ServerRestHandler {
void handle(ResteasyReactiveRequestContext requestContext);
}
class SecurityContextOverrideHandler implements ServerRestHandler {
void handle(ResteasyReactiveRequestContext requestContext);
}Observability Handlers:
package io.quarkus.resteasy.reactive.server.runtime.observability;
class ObservabilityHandler implements ServerRestHandler {
String getTemplatePath();
void setTemplatePath(String templatePath);
void handle(ResteasyReactiveRequestContext requestContext);
}Compression Handlers:
package io.quarkus.resteasy.reactive.server.runtime;
class ResteasyReactiveCompressionHandler implements ServerRestHandler {
HttpCompression getCompression();
void setCompression(HttpCompression compression);
void handle(ResteasyReactiveRequestContext requestContext);
}Quarkus REST provides seamless CDI integration through Arc, Quarkus's CDI implementation.
package io.quarkus.resteasy.reactive.server.runtime;
@Singleton
class QuarkusContextProducers {
@Produces
@RequestScoped
HttpServerResponse httpServerResponse();
@Produces
@ApplicationScoped
Providers providers();
@Produces
@RequestScoped
CloserImpl closer();
@Disposes
void closeCloser(CloserImpl closer);
}These producers make JAX-RS context types available for CDI injection.
In Quarkus REST, @Context and @Inject are interchangeable for context types:
// Both work identically:
@Context UriInfo uriInfo;
@Inject UriInfo uriInfo;Context objects like UriInfo, HttpHeaders, and SecurityContext are request-scoped, ensuring each request has its own instance.
REST resource classes can use any CDI scope:
@ApplicationScoped - Singleton, shared across requests@RequestScoped - New instance per request@Dependent - New instance per injection point (default)Quarkus REST is built on reactive principles using Smallrye Mutiny.
Methods can return reactive types:
@GET
public Uni<Book> getAsync() {
return bookService.findAsync();
}
@GET
public Multi<Book> stream() {
return bookService.streamAll();
}
@GET
public CompletionStage<Book> getCompletionStage() {
return bookService.findAsyncJava();
}Security checks return Uni<SecurityIdentity>:
package io.quarkus.resteasy.reactive.server.runtime.security;
@Singleton
class EagerSecurityContext {
Uni<SecurityIdentity> getDeferredIdentity();
Uni<SecurityIdentity> getPermissionCheck(
ResteasyReactiveRequestContext requestContext,
SecurityIdentity identity
);
}Exception mappers can return reactive responses:
@ServerExceptionMapper
public Uni<Response> handleException(CustomException ex) {
return logService.logAsync(ex)
.onItem().transform(logId ->
Response.status(500)
.entity(new ErrorResponse(logId))
.build()
);
}By default, REST methods execute on the Vert.x event loop (non-blocking). Methods can opt into worker threads:
@GET
@Blocking // Execute on worker thread
public String blockingOperation() {
return performBlockingIO();
}
@GET
@RunOnVirtualThread // Execute on virtual thread (JDK 21+)
public String virtualThreadOperation() {
return performBlockingIO();
}Quarkus REST is built on Vert.x for the HTTP layer.
Direct access to Vert.x types:
package io.vertx.core.http;
interface HttpServerRequest {
String uri();
String path();
HttpMethod method();
MultiMap headers();
SocketAddress remoteAddress();
}
interface HttpServerResponse {
HttpServerResponse setStatusCode(int statusCode);
HttpServerResponse putHeader(String name, String value);
void end();
}package io.vertx.ext.web;
interface RoutingContext {
HttpServerRequest request();
HttpServerResponse response();
Map<String, Object> data();
}REST resources can inject Vert.x types:
@GET
public Response get(@Context HttpServerRequest request) {
String remoteIp = request.remoteAddress().host();
return Response.ok().build();
}
@GET
public void customResponse(@Context HttpServerResponse response) {
response.setStatusCode(200);
response.putHeader("X-Custom", "value");
response.end("Custom response");
}WebSocket endpoints use Vert.x ServerWebSocket:
package io.quarkus.resteasy.reactive.server.runtime.websocket;
class VertxWebSocketParamExtractor implements ParameterExtractor {
Object extractParameter(ResteasyReactiveRequestContext requestContext);
}Quarkus REST performs extensive build-time processing for optimal runtime performance.
Build-time logic uses the Recorder pattern:
package io.quarkus.resteasy.reactive.server.runtime;
class ResteasyReactiveRecorder {
RuntimeValue<Deployment> createDeployment(...);
RuntimeValue<RestInitialHandler> restInitialHandler(...);
Handler<RoutingContext> handler(...);
void registerExceptionMapper(...);
}Recorders execute at build time to generate optimized runtime structures.
package io.quarkus.resteasy.reactive.server.runtime;
interface ResteasyReactiveInitialiser {
void init(Deployment deployment);
}Generated initialization code runs at build time.
All reflection is eliminated at build time:
This enables native image compilation and improves performance.
package io.quarkus.resteasy.reactive.server.runtime;
class QuarkusResteasyReactiveRequestContext extends ResteasyReactiveRequestContext {
protected void invokeHandler(int pos);
}Handler invocation uses monomorphic instance checks instead of polymorphic calls for better JIT compilation.
Security checks happen early in the handler chain, before method invocation, avoiding repeated checks:
package io.quarkus.resteasy.reactive.server.runtime;
abstract class StandardSecurityCheckInterceptor {
@AroundInvoke
Object intercept(InvocationContext ic);
}CDI interceptors detect if security already checked and skip redundant work.
Security identity is resolved lazily only when needed:
package io.quarkus.resteasy.reactive.server.runtime.security;
@Singleton
class EagerSecurityContext {
Uni<SecurityIdentity> getDeferredIdentity();
}package io.quarkus.resteasy.reactive.server.runtime;
class ResteasyReactiveRecorder {
static Supplier<Executor> VTHREAD_EXECUTOR_SUPPLIER;
}JDK 21+ virtual threads provide scalable blocking operations.
Quarkus REST provides multiple extension points:
Add custom handlers:
@ApplicationScoped
public class CustomHandlerChainCustomizer implements HandlerChainCustomizer {
public List<ServerRestHandler> handlers(Phase phase, ResourceClass resourceClass, ServerResourceMethod resourceMethod) {
// Return custom handlers
}
}Custom exception handling:
@ServerExceptionMapper
public Response handleException(CustomException ex) {
return Response.status(500).build();
}Custom serialization:
@Provider
public class CustomMessageBodyWriter implements MessageBodyWriter<CustomType> {
// Serialization logic
}Custom parameter extraction:
public class CustomParamExtractor implements ParameterExtractor {
public Object extractParameter(ResteasyReactiveRequestContext context) {
// Extraction logic
}
}Default execution happens on Vert.x event loop threads (non-blocking):
Blocking operations use worker threads:
@Blocking
@GET
public String blockingOp() {
return performBlockingIO();
}Worker pool size configurable via quarkus.thread-pool.max-threads.
JDK 21+ enables virtual threads for scalable blocking:
@RunOnVirtualThread
@GET
public String virtualThreadOp() {
return performBlockingIO();
}Quarkus REST is fully compatible with GraalVM native images:
┌─────────────────────────────────────────────────────┐
│ 1. HTTP Request arrives at Netty │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 2. Vert.x Event Loop Thread │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 3. RestInitialHandler - Create Request Context │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 4. Activate Request Scope + Security Setup │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 5. AFTER_PRE_MATCH Handler Chain │
│ - Request logging │
│ - Early filtering │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 6. Resource Method Matching │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 7. AFTER_MATCH Handler Chain │
│ - EagerSecurityHandler (security checks) │
│ - ObservabilityHandler (metrics/tracing) │
│ - ResteasyReactiveCompressionHandler │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 8. Parameter Extraction │
│ - Path/Query/Header params │
│ - Request body deserialization │
│ - Context injection │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 9. Resource Method Invocation │
│ (on event loop or worker/virtual thread) │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 10. AFTER_METHOD_INVOKE Handler Chain │
│ - Response modification │
│ - WebSocket upgrade │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 11. Response Serialization │
│ - MessageBodyWriter selection │
│ - JSON/XML/etc serialization │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 12. HTTP Response Transmission │
│ - Compression (if enabled) │
│ - Vert.x socket write │
└────────────────┬────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 13. Request Scope Deactivation │
│ - Closer cleanup │
│ - CDI @Disposes │
└─────────────────────────────────────────────────────┘This architecture delivers high performance, low memory usage, and excellent scalability while maintaining compatibility with Jakarta REST standards.